Cosas que NO me gustan de Laravel Livewire... Su "Complejidad"

Llegó el momento en el cual quiero hablar un poquito mal de Livewire, ya que casi siempre hablo mal de Inertia cuando los comparo. Siempre hago estas comparaciones porque se supone que son tecnologías hermanas: ambas salieron junto con Jetstream, en su primera presentación por parte del equipo de Laravel (creo que fue con la versión 7). A partir de ahí, cada una ha tomado caminos algo distintos.

Sin embargo, sigue siendo interesante compararlos, porque cuando vas a crear un nuevo proyecto en Laravel, puedes decidir entre usar:

  • Laravel base,
  • Laravel con Inertia + Vue,
  • Laravel con Inertia + React,
  • Laravel con Livewire.

No hay una mejor que otra en términos absolutos, aunque —en mi humilde opinión— Livewire es un poco más todo terreno que Inertia. Pero como siempre digo: todo tiene sus ventajas y desventajas, dependiendo del tipo de proyecto que quieras hacer.

Los "problemas" de Livewire: Complejidad y Abstracto

Ahora sí, vamos con lo que no me gusta tanto de Livewire.

La principal crítica que tengo es la complejidad que se genera entre los componentes de Laravel (Livewire), Blade y Alpine.js. Siento que todo se empieza a solapar.

Por ejemplo:
No sabes en qué momento estás trabajando con JavaScript de Livewire, y en qué momento estás en Alpine. Te muestro un caso:

<div class="flex" x-data="{ active: $wire.entangle('step') }" class="flex flex-col max-w-sm mx-auto">

Cuando quieres lograr comunicación bidireccional entre cliente y servidor, terminas entrando en una maraña de x-data, @entangle, get etc. Esto no pasa en Inertia, donde simplemente defines un prop, pasas los datos y te olvidas:

<script setup>
import Layout from './Layout'
import { Head } from '@inertiajs/vue3'

defineProps({ user: Object })
</script>

<template>
  <Layout>
    <Head title="Welcome" />
    <h1>Welcome</h1>
    <p>Hello {{ user.name }}, welcome to your first Inertia app!</p>
  </Layout>
</template>

Aquí, sin embargo, quieres saber el valor del state, porque es el que indica el "paso por paso" de un formulario, y al actualizar el estado en el servidor, también quieres actualizarlo en el cliente. Pero como el get no lo puedes leer directamente, se pierde el valor y terminas escribiendo lógica extra solo para mantener la sincronización.

¿Más Opciones? Sí. ¿Más Código? También

La ventaja de Livewire es que al estar más integrado a Laravel, tienes más opciones. Pero esas opciones a veces hacen que el código sea más complicado de mantener.

En Inertia, como todo es directamente Vue o React, es mucho más claro qué pasa y dónde pasa. En cambio, con Livewire tienes lógica en Blade, lógica en componentes, lógica en Alpine y lógica en PHP. Cuesta seguirle el rastro a todo.

Otro caso que me resultó complicado es la comunicación entre componentes padre e hijo (y viceversa) en Livewire.

Por ejemplo, en el componente de "paso por paso", que forma parte del curso y libro que puedes buscar en academia, tengo un StepEvent que se lanza desde el hijo, y lo escucha el padre. El padre es el componente general, y los hijos son:

// parent
class General extends Component
{
  protected $listeners = ['stepEvent'];
}

//child
class Company extends Component
{
    ***

    function back() {
        $this->dispatch('stepEvent', 1);
    }

Cuando se está en uno de esos pasos y el usuario interactúa, el hijo lanza un evento al padre. El padre escucha con un @listener y ejecuta el método correspondiente.

Esto puede resultar confuso la primera vez que alguien lo lee, sobre todo si no conoce nuestro código. ¿Cómo documentas algo así? Se vuelve complicado.

Comunicación Inversa: Padre a Hijo

En el curso/libro también mostré otro ejemplo más interesante: el carrito de compras.

Tienes un componente Cart (padre) que contiene varios CartItem (hijos).

Pero esta vez, quiero que el padre pase información hacia el hijo, concretamente el post o ítem del carrito:

// parent
class Cart extends Component
{
    function addItem()
    {
        $this->dispatch('addItemToCart', $this->post);
    }
}

// child
class CartItem extends Component
{
    ***
    #[On('addItemToCart')]
    function add(Post $post, int $count = 1)
    {***}

Como es una entidad que se maneja en el padre, necesito pasarla hacia el hijo para que lo agregue o modifique. No quiero complicarte aquí con el detalle técnico, pero básicamente es eso.

¿Demasiadas Opciones?

No estoy criticando por criticar, me encanta Livewire. Pero sí tiene una curva de aprendizaje más alta si lo comparamos con Inertia, y es precisamente por estas lógicas que pueden parecer algo abstractas.

Además, hay múltiples formas de hacer lo mismo.

Por ejemplo:
Cuando trabajas con filtros y eventos, puedes definirlos como:

  • Etiquetas con @,
  • Decoradores como @url,
  • O directamente como propiedades públicas.

Esto te da más opciones, pero también hace más complicada la programación.

Acepto recibir anuncios de interes sobre este Blog.

Hablo sobre un aspecto que NO me gusta de Laravel Livewire, como lo es la complejidad adicional que es debido a las gran flexibilidad del stack.

- Andrés Cruz

In english