Unidad 5.22 - Livewire: Comunicación entre Componentes con Eventos
5.22.1 Introducción
En Livewire, la comunicación entre componentes es una de las funcionalidades más poderosas. A través del sistema de eventos, los componentes pueden emitir mensajes que pueden ser escuchados por otros componentes, lo que permite una interacción fluida entre diferentes partes de la interfaz de usuario sin recargar la página.
Esta capacidad de comunicar componentes entre sí sin depender de JavaScript es crucial para la creación de aplicaciones dinámicas y reactivas. En esta unidad, vamos a construir una aplicación paso a paso que involucra tres componentes Livewire que se comunicarán entre sí mediante eventos, todo esto usando el patrón MVVM (Model-View-ViewModel).
Vamos a crear un carrito de compras como ejemplo práctico. El carrito permitirá a los usuarios añadir productos y ver el total actualizado, además de tener la opción de filtrar productos por nombre.
🧭 Flujo básico de eventos en Livewire
Los eventos en Livewire permiten que un componente "emita" un evento que puede ser "escuchado" por otros componentes. A continuación, mostramos un flujo básico de cómo funcionan los eventos entre los componentes:
Flujo de eventos en Livewire
sequenceDiagram
participant Usuario
participant ProductosComponent
participant Livewire
participant CartItemsComponent
Usuario->>ProductosComponent: Click en "Agregar al carrito"
ProductosComponent->>Livewire: dispatch('cartUpdated')
Livewire->>CartItemsComponent: escucha 'cartUpdated'
CartItemsComponent->>CartItemsComponent: actualizar vista y total
En este diagrama:
- El Usuario realiza una acción, como hacer clic en el botón de "Agregar al carrito".
- El ProductosComponent emite el evento
cartUpdatedusando el métododispatch(). - Livewire se encarga de gestionar el evento y lo transmite al componente receptor, en este caso, el CartItemsComponent.
- El CartItemsComponent actualiza su vista para reflejar el cambio en el carrito.
Este es el flujo que vamos a usar para integrar los diferentes componentes y hacerlos reaccionar a los cambios de estado.
Flujo de eventos en Livewire
sequenceDiagram
participant Usuario
participant ProductosComponent
participant Livewire
participant CartItemsComponent
participant NavComponent
Usuario->>ProductosComponent: Click en "Agregar al carrito"
ProductosComponent->>Livewire: dispatch('cartUpdated', productoId)
Livewire->>CartItemsComponent: escucha 'cartUpdated'
CartItemsComponent->>CartItemsComponent: Actualizar elementos del carrito
CartItemsComponent->>Livewire: dispatch('updateTotal', total)
Livewire->>ProductosComponent: Escucha 'updateTotal'
ProductosComponent->>ProductosComponent: Actualiza la vista con el total
Usuario->>NavComponent: Escribe búsqueda
NavComponent->>Livewire: dispatch('filtro', busqueda)
Livewire->>ProductosComponent: Escucha 'filtro'
ProductosComponent->>ProductosComponent: Filtra productos
ProductosComponent->>Livewire: dispatch('cartUpdated') %% Si el carrito cambia, actualizar vista
5.22.2 Estructura del proyecto
En esta unidad, vamos a crear los siguientes componentes y estructuras:
- Migraciones y modelos: Definiremos las tablas necesarias para los productos, carritos y la relación entre ellos.
-
Componentes Livewire:
-
ProductosComponent: Lista los productos y permite agregarlos al carrito.
- CartItemsComponent: Muestra los productos añadidos al carrito y el total.
- NavComponent: Permite buscar productos y filtrar la lista.
- Vistas integradas con Bootstrap: Usaremos Bootstrap para mejorar el diseño y hacer que la aplicación sea más atractiva.
- Sistema de eventos entre componentes: Utilizaremos eventos para que los componentes se comuniquen entre sí de forma eficiente.
5.22.3 Migraciones y Modelos
Para gestionar los datos de productos y carritos, necesitamos crear las migraciones y modelos adecuados. Las migraciones nos permitirán definir la estructura de nuestras tablas en la base de datos.
Paso 1: Crear las Migraciones
Primero, ejecutamos los siguientes comandos para generar los modelos y las migraciones:
Paso 2: Migración para la tabla products
La tabla products almacenará la información de los productos que los usuarios pueden agregar al carrito. Necesitamos los campos title, description, price e image.
Contenido de la migración para products
Paso 3: Migración para la tabla carts
La tabla carts almacenará la información del carrito. En este caso, solo necesitamos un campo id y las fechas created_at y updated_at.
contenido de la migración para carts
Paso 4: Migración para la tabla cart_items
La tabla cart_items será la tabla intermedia que almacenará la relación entre los productos y el carrito. Incluye los campos product_id, cart_id, quantity y price.
contenido de la migración para cart_items
Paso 5: Ejecutar las Migraciones
Una vez que las migraciones estén configuradas, ejecutamos:
Esto creará las tablas necesarias en la base de datos.
Paso5: Modelos
1. Modelo Product
Este modelo representa los productos que los usuarios pueden agregar al carrito. En el modelo se define la relación belongsToMany con el carrito, ya que un producto puede estar en muchos carritos.
Contenido del modelo Product
2. Modelo Cart
El modelo Cart representa un carrito de compras. Un carrito puede contener múltiples productos, y es utilizado para gestionar los elementos en el carrito.
Contenido del modelo Cart
3. Modelo CartItem
El modelo CartItem representa un elemento dentro de un carrito. En este modelo, almacenamos la cantidad de un producto específico dentro del carrito, junto con su precio.
Contenido del modelo CartItem
4. Modelo CartItem (con campos adicionales)
Este modelo será utilizado para gestionar la relación entre los productos y el carrito, además de almacenar los campos quantity (cantidad) y price (precio). Específicamente, será necesario para la tabla intermedia cart_items.
Recuerda que estos modelos gestionan la relación entre productos, carritos y los elementos dentro del carrito, utilizando la relación belongsToMany y withPivot para acceder a los campos adicionales de la tabla intermedia (cart_items).
5.22.4 Seeders y Factorys
Para poblar la base de datos con productos de ejemplo, vamos a crear un seeder y una factory para los productos.
Paso 1: Crear el Seeder para Productos
Ejecutamos el siguiente comando para crear el seeder:
En database/seeders/ProductsSeeder.php, añadimos el siguiente código para generar productos de ejemplo:
Contenido del Seeder para Productos
Paso 2: Crear la Factory para Product
Ejecutamos el siguiente comando para crear la factory:
En database/factories/ProductFactory.php, definimos los campos que se generarán para los productos:
Contenido de la Factory para Product
En el ejemplo anterior, la image se selecciona aleatoriamente de un conjunto de imágenes predefinidas. Asegúrate de que las imágenes estén disponibles en la carpeta storage/app/public/img de tu proyecto.
Las imagenes son las siguientes:
| Imagen 1 | Imagen 2 | Imagen 3 |
|---|---|---|
![]() |
![]() |
![]() |
Puedes descargarlas y guardarlas en la carpeta storage/app/public/img de tu proyecto.
Seeder para Cart
Ejecuta el siguiente comando para crear el seeder:
Contenido del Seeder para Cart
En database/seeders/CartSeeder.php, añade el siguiente código:
Contenido del Seeder para Cart
Este seeder simplemente crea una entrada en la tabla carts con las fechas created_at y updated_at actuales. Como mencionamos, en este ejemplo simplificado solo existe un carrito
Paso 3: Ejecutar los Seeders
Registramos los seeders en DatabaseSeeder.php:
Contenido de DatabaseSeeder.php
Luego ejecutamos el comando para poblar la base de datos:
5.22.5 Creación de Componentes Livewire
Ahora que la base de datos está configurada y poblada, vamos a crear los componentes Livewire necesarios para nuestra aplicación.
Paso 1: Crear los Componentes
Ejecutamos los siguientes comandos para crear los tres componentes principales:
php artisan make:livewire ProductsComponent
php artisan make:livewire CartItemsComponent
php artisan make:livewire NavComponent
1️⃣ ProductsComponent
Este componente es el responsable de mostrar la lista de productos y agregar productos al carrito.
Lógica del Componente
En app/Http/Livewire/ProductsComponent.php, definimos la lógica:
Contenido del Componente ProductsComponent
Vista del Componente
En resources/views/livewire/products-component.blade.php, creamos la vista que muestra los productos:
Contenido de la Vista products-component
2️⃣ CartItemsComponent
Este componente muestra los productos añadidos al carrito y el total.
Lógica del Componente
En app/Http/Livewire/CartItemsComponent.php, gestionamos los elementos del carrito:
Contenido del Componente CartItemsComponent
Vista del Componente
En resources/views/livewire/cart-items-component.blade.php, mostramos el carrito:
Contenido de la Vista cart-items-component
3️⃣ NavComponent
Este componente permite filtrar los productos por nombre.
Lógica del Componente
En app/Http/Livewire/NavComponent.php, gestionamos la búsqueda de productos:
Contenido del Componente NavComponent
Vista del Componente
En resources/views/livewire/nav-component.blade.php:
Contenido de la Vista nav-component
5.22.6 Eventos entre Componentes
En este apartado vamos a ver detalles de los eventos en livewire que no hemos utilizado en el proyecto de ejemplo que estamos desarrollando.
- Cómo emitir eventos con parámetros
- Cómo escuchar eventos con parámetros
- Escuchar múltiples eventos
Cómo emitir eventos con parámetros Cuando se emite un evento con dispatch(), puedes incluir datos adicionales, como el ID del producto, la cantidad, el precio, etc. Este enfoque es útil para eventos que necesitan pasar información más allá de un simple nombre de evento.
Cómo emitir eventos con parámetros
Cómo escuchar eventos con parámetros
Luego, en el componente que escucha el evento (CartItemsComponent), puedes acceder a los datos pasados como parámetros y usar esos datos en la lógica:
Cómo escuchar eventos con parámetros
Escuchar múltiples eventos Si un componente necesita escuchar varios eventos, puedes hacerlo de la siguiente manera:
Cómo escuchar múltiples eventos
Aquí, el componente escucha tres eventos diferentes (cartUpdated, filtro, updateTotal) y ejecuta diferentes métodos según el evento recibido.
Registrar eventos dinámicos
Podemos crear un método getListeners() en el componente para registrar los eventos de forma dinámica. Esto es útil si queremos que los eventos se registren de manera más organizada o si queremos añadir lógica adicional al registro de eventos.
Cómo registrar eventos dinámicos
Esta lógica permitiría al componenente variar los eventos que escucha en función de la lógica interna del componente, lo que puede ser útil en aplicaciones más complejas.
5.22.6 Integración Final de Componentes
1. Crear el Layout Base con Bootstrap
En Laravel, el layout base generalmente se coloca en resources/views/layouts/app.blade.php. Este archivo es utilizado por las vistas de la aplicación para aplicar un diseño consistente.
Contenido de app.blade.php
Contenido del Layout app.blade.php
Explicación del Layout
- Meta etiquetas: Se incluye la meta etiqueta para la codificación en UTF-8 y para el diseño responsivo.
- Bootstrap: Se incluyen los archivos CSS y JS de Bootstrap 5 desde un CDN para el diseño responsivo.
- @livewireStyles y @livewireScripts: Estas directivas son esenciales para que Livewire funcione correctamente en el frontend.
@livewireStylesse incluye en la sección<head>, y@livewireScriptsse coloca justo antes de cerrar la etiqueta</body>. - Navbar: Se crea una barra de navegación utilizando las clases de Bootstrap. Este ejemplo incluye enlaces básicos a "Inicio", "Productos" y "Carrito", pero puedes modificarlo según las necesidades de tu aplicación.
- @yield('content'): Esta directiva es donde se insertará el contenido de cada vista específica que extienda este layout. Esto permite tener una estructura común en todas las páginas de la aplicación.
2. Usar el Layout en las Vistas
Con el layout base creado, ahora puedes usarlo en las vistas específicas de tu aplicación. Por ejemplo, en resources/views/welcome.blade.php, puedes hacer lo siguiente:
Contenido de welcome.blade.php
Explicación:
- @extends('layouts.app'): Esta directiva hace que la vista
welcome.blade.phpextienda el layoutapp.blade.php. Esto significa que la vista tomará la estructura de navegación, estilos y scripts definidos en el layout base. - @section('content'): Todo el contenido de la vista se colocará dentro del
@yield('content')del layout base. Esto permite que cada vista tenga su propio contenido dentro de la estructura común.
4. Conclusión
Ahora tienes un layout base utilizando Bootstrap que incluye una barra de navegación, un área para el contenido específico de la vista, y el soporte necesario para los componentes de Livewire. Puedes extender este layout para cualquier otra página de tu aplicación, manteniendo una estructura coherente y profesional en todo el sitio.
5.22.7 Pruebas de Integración
Realizamos las siguientes pruebas:
- Agregar productos al carrito: Al hacer clic en "Agregar al carrito", el producto se agrega correctamente al carrito.
- Filtrar productos: Al escribir un término de búsqueda en
NavComponenty hacer clic en "Filtrar",ProductosComponentactualiza la lista de productos mostrados. - Actualizar el total del carrito: Al agregar o eliminar productos del carrito, el total se actualiza correctamente en
CartItemsComponent.
5.22.8 Conclusión
Con este enfoque hemos logrado crear una aplicación modular utilizando Livewire, donde los componentes se comunican entre sí mediante eventos. Gracias a Livewire y su sistema de eventos, los datos se sincronizan en tiempo real sin recargar la página ni escribir código JavaScript.
Esta es una forma muy eficiente de manejar la interactividad en aplicaciones web modernas y complejas, lo que nos permite construir aplicaciones dinámicas y escalables.


