Saltearse al contenido

Componentes

Los componentes son los bloques de construcción de su aplicación Livewire. Combinan estado y comportamiento para crear piezas reutilizables de interfaz de usuario para su front-end. Aquí, cubriremos los fundamentos de la creación y renderización de componentes.

Creando componentes

Un componente Livewire es simplemente una clase PHP que extiende Livewire\Component. Puedes crear archivos de componentes a mano o usar el siguiente comando de Artisan:

Ventana de terminal
php artisan make:livewire CreatePost

Si prefieres los nombres en mayúsculas(kebab-cased), también puede utilizarlos:

Ventana de terminal
php artisan make:livewire create-post

Después de ejecutar este comando, Livewire creará dos nuevos archivos en su aplicación. El primero será la clase del componente: app/Livewire/CreatePost.php

Ventana de terminal
<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public function render()
{
return view('livewire.create-post');
}
}

La segunda será la vista Blade del componente: resources/views/livewire/create-post.blade.php

<div>
{{-- ... --}}
</div>

Puede utilizar la sintaxis de espacio de nombres(namespaces) o la anotación por puntos para crear sus componentes en subdirectorios. Por ejemplo, los siguientes comandos crearán un componente CreatePost en el subdirectorio Posts:

Ventana de terminal
php artisan make:livewire Posts\\CreatePost
php artisan make:livewire posts.create-post

Componentes en línea (Inline components)

Si tu componente es bastante pequeño, puede querer crear un componente inline. Los componentes en línea son componentes Livewire de un solo archivo cuya plantilla de vista está contenida directamente en el método render() en lugar de en un archivo separado:

<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public function render()
{
return <<<'HTML'
<div>
{{-- Tu plantilla Blade va aquí.. --}}
</div>
HTML;
}
}

Puedes crear componentes inline añadiendo la opción --inline al comando make:livewire:

Ventana de terminal
php artisan make:livewire CreatePost --inline

Omitiendo el método render

Para reducir el boilerplate en sus componentes, puede omitir el método render() por completo y Livewire utilizará su propio método render() subyacente, que devuelve una vista con el nombre convencional correspondiente a su componente:

<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
//
}

Si el componente anterior se renderiza en una página, Livewire determinará automáticamente que debe renderizarse utilizando la plantilla livewire.create-post.

Personalización de los stubs de componentes

Puede personalizar los archivos (o stubs) que Livewire utiliza para generar nuevos componentes ejecutando el siguiente comando:

Ventana de terminal
php artisan livewire:stubs

Esto creará cuatro nuevos archivos en su aplicación:

  • stubs/livewire.stub : Utilizado para generar nuevos componentes
  • stubs/livewire.inline.stub : Utilizado para generar componentes en línea
  • stubs/livewire.test.stub : Utilizado para generar archivos de prueba
  • stubs/livewire.view.stub : Utilizado para generar vistas de componentes

Aunque estos archivos se encuentren en tu aplicación, puedes utilizar el comando make:livewire Artisan y Livewire utilizará automáticamente tus stubs personalizados cuando genere los archivos.

Configuración de propiedades

Los componentes Livewire tienen propiedades que almacenan datos y a las que se puede acceder fácilmente dentro de la clase del componente y la vista Blade. Esta sección trata los conceptos básicos para añadir una propiedad a un componente y utilizarla en su aplicación.

Para añadir una propiedad a un componente Livewire, declare una propiedad pública en la clase de su componente. Por ejemplo, vamos a crear una propiedad $title en el componente CreatePost:

<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public $title = 'Post title...';
public function render()
{
return view('livewire.create-post');
}
}

Acceso a las propiedades en la vista

Las propiedades de los componentes se ponen automáticamente a disposición de la vista Blade del componente. Puede hacer referencia a ellas utilizando la sintaxis estándar de Blade. Aquí mostraremos el valor de la propiedad $title:

<div>
<h1>Title: "{{ $title }}"</h1>
</div>

La salida renderizada de este componente sería:

<div>
<h1>Title: "Post title..."</h1>
</div>

Compartir datos adicionales con la vista

Además de acceder a las propiedades desde la vista, puedes pasar explícitamente datos a la vista desde el método render(), como harías normalmente desde un controlador. Esto puede ser útil cuando quieras pasar datos adicionales sin almacenarlos primero como una propiedad, ya que las propiedades tienen implicaciones específicas de rendimiento y seguridad.

Para pasar datos a la vista en el método render(), puedes utilizar el método with() en la instancia de la vista. Por ejemplo, digamos que quieres pasar el nombre del autor de la entrada a la vista. En este caso, el autor de la entrada es el usuario autenticado actualmente:

<?php
namespace App\Livewire;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class CreatePost extends Component
{
public $title;
public function render()
{
return view('livewire.create-post')->with([
'author' => Auth::user()->name,
]);
}
}

Ahora puede acceder a la propiedad $author desde la vista Blade del componente:

<div>
<h1>Title: {{ $title }}</h1>
<span>Author: {{ $author }}</span>
</div>

Añadir wire:key a los bucles @foreach

Cuando realice un bucle a través de los datos de una plantilla Livewire utilizando @foreach, debe añadir un atributo wire:key único al elemento raíz renderizado por el bucle.

Sin un atributo wire:key presente dentro de un bucle Blade, Livewire no podrá emparejar correctamente los elementos antiguos con sus nuevas posiciones cuando cambie el bucle. Esto puede causar muchos problemas difíciles de diagnosticar en su aplicación.

Por ejemplo, si está haciendo un bucle a través de un array de entradas, puede establecer el atributo wire:key al ID de la entrada:

<div>
@foreach ($posts as $post)
<div wire:key="{{ $post->id }}">
<!-- ... -->
</div>
@endforeach
</div>

Si está haciendo un bucle a través de un array que está renderizando componentes Livewire puede establecer la clave como un atributo del componente :key() o pasar la clave como tercer argumento cuando utilice la directiva @livewire.

<div>
@foreach ($posts as $post)
<livewire:post-item :$post :key="$post->id">
@livewire(PostItem::class, ['post' => $post], key($post->id))
@endforeach
</div>

Vinculación de entradas a propiedades (Binding Inputs)

Una de las características más potentes de Livewire es la “vinculación de datos”: la capacidad de mantener automáticamente las propiedades sincronizadas con las entradas del formulario en la página.

Vamos a vincular la propiedad $title del componente CreatePost a una entrada de texto utilizando la directiva wire:model:

<form>
<label for="title">Title:</label>
<input type="text" id="title" wire:model="title">
</form>

Cualquier cambio realizado en la entrada de texto se sincronizará automáticamente con la propiedad $title de su componente Livewire.

Las propiedades de Livewire son extremadamente potentes y es importante entenderlas. Para más información, consulte la documentación de las propiedades de Livewire.

Llamada a acciones

Las acciones son métodos dentro de su componente Livewire que manejan las interacciones del usuario o realizan tareas específicas. Suelen ser útiles para responder a los clics de los botones o al envío de formularios en una página.

Para aprender más sobre las acciones, vamos a añadir una acción save al componente CreatePost:

<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Post;
class CreatePost extends Component
{
public $title;
public function save()
{
$post = Post::create([
'title' => $this->title
]);
return redirect()->to('/posts')
->with('status', 'Post created!');
}
public function render()
{
return view('livewire.create-post');
}
}

A continuación, vamos a llamar a la acción de save desde la vista Blade del componente añadiendo la directiva wire:submit al elemento <form>:

<form wire:submit="save">
<label for="title">Title:</label>
<input type="text" id="title" wire:model="title">
<button type="submit">Guardar</button>
</form>

Cuando se pulse el botón “Guardar”, se ejecutará el método save() de su componente Livewire y su componente se volverá a renderizar.

Para seguir aprendiendo sobre las acciones Livewire, visite la documentación de acciones.

Renderización de componentes

Existen dos formas de renderizar un componente Livewire en una página:

  • Incluirlo dentro de una vista Blade existente
  • Asignarlo directamente a una ruta como un componente de página completa

Veamos la primera forma de renderizar su componente, ya que es más sencilla que la segunda.

Puede incluir un componente Livewire en sus plantillas Blade utilizando la sintaxis<livewire:component-name />:

<livewire:create-post />

Si la clase del componente está anidada a mayor profundidad dentro del directorio app/Livewire/, puede utilizar el carácter . para indicar la anidación de directorios. Por ejemplo, si asumimos que un componente se encuentra en app/Livewire/EditorPosts/CreatePost.php, podemos renderizarlo así:

<livewire:editor-posts.create-post />

Pasar datos a los componentes

Para pasar datos externos a un componente Livewire, puede utilizar atributos en la etiqueta del componente. Esto es útil cuando se desea inicializar un componente con datos específicos.

Para pasar un valor inicial a la propiedad $title del componente CreatePost, puede utilizar la siguiente sintaxis:

<livewire:create-post title="Titulo Inicial" />

Si necesita pasar valores dinámicos o variables a un componente, puede escribir expresiones PHP en atributos de componentes anteponiendo dos puntos al atributo:

<livewire:create-post :title="$initialTitle" />

Los datos que se pasan a los componentes se reciben a través del gancho del ciclo de vida mount() como parámetros del método. En este caso, para asignar el parámetro $title a una propiedad, escribirías un método mount() como el siguiente:

<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public $title;
public function mount($title = null)
{
$this->title = $title;
}
// ...
}

En este ejemplo, la propiedad $title se inicializará con el valor “Título inicial”.

Puede pensar en el método mount() como un constructor de clase. Se ejecuta en la carga inicial del componente, pero no en peticiones posteriores dentro de una página. Puede obtener más información sobre mount() y otros útiles Hooks del ciclo de vida en la documentación del ciclo de vida.

Para reducir el código repetitivo en sus componentes, puede omitir el método mount() y Livewire establecerá automáticamente cualquier propiedad en su componente con nombres que coincidan con los valores pasados:

<?php
namespace App\Livewire;
use Livewire\Component;
class CreatePost extends Component
{
public $title;
// ...
}

Esto es efectivamente lo mismo que asignar $title dentro de un método mount().

Componentes de página completa (Full Page Components)

Livewire le permite asignar componentes directamente a una ruta en su aplicación Laravel. Estos se llaman “componentes de página completa”. Puede utilizarlos para construir páginas independientes con lógica y vistas, totalmente encapsuladas dentro de un componente Livewire.

Para crear un componente de página completa, defina una ruta en su archivo routes/web.php y utilice el método Route::get() para asignar el componente directamente a una URL específica. Por ejemplo, imaginemos que desea renderizar el componente CreatePost en la ruta dedicada /posts/create.

Puede conseguirlo añadiendo la siguiente línea a su archivo routes/web.php:

use App\Livewire\CreatePost;
Route::get('/posts/create', CreatePost::class);

Ahora, cuando visite la ruta /posts/create en su navegador, el componente CreatePost se mostrará como un componente de página completa.

Archivos Layout

Recuerde que los Full Page components de utilizarán el layout de su aplicación, normalmente definido en el archivo resources/views/components/layouts/app.blade.php.

Puede crear este archivo si aún no existe ejecutando el siguiente comando:

Ventana de terminal
php artisan livewire:layout

Este comando generará un archivo llamado resources/views/components/layouts/app.blade.php.

Asegúrese de haber creado un archivo Blade en esta ubicación y de haber incluido un marcador de posición {{ $slot }}:

resources/views/components/layouts/app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Page Title' }}</title>
</head>
<body>
{{ $slot }}
</body>
</html>

Configuración global del layout

Para utilizar un diseño personalizado en todos sus componentes, puede establecer la clave de diseño en config/livewire.php en la ruta de su diseño personalizado, relativa a resources/views. Por ejemplo

'layout' => 'layouts.app',

Con la configuración anterior, Livewire renderizará componentes de página completa dentro del archivo de diseño: resources/views/layouts/app.blade.php.

Configuración del layout por componente Para utilizar un layout diferente para un componente específico, puede colocar el atributo #[Layout] de Livewire sobre el método render( del componente, pasándole la ruta de vista relativa de su diseño personalizado:

<?php
namespace App\Livewire;
use Livewire\Attributes\Layout;
use Livewire\Component;
class CreatePost extends Component
{
// ...
#[Layout('layouts.app')]
public function render()
{
return view('livewire.create-post');
}
}

O si lo prefiere, puede utilizar este atributo encima de la declaración de la clase:

<?php
namespace App\Livewire;
use Livewire\Attributes\Layout;
use Livewire\Component;
#[Layout('layouts.app')]
class CreatePost extends Component
{
// ...
}

Los atributos PHP sólo admiten valores literales. Si necesita pasar un valor dinámico, o prefiere esta sintaxis alternativa, puede utilizar el método fluent ->layout() en el método render() del componente:

public function render()
{
return view('livewire.create-post')
->layout('layouts.app');
}

Como alternativa, Livewire permite utilizar archivos de diseño Blade tradicionales con @extends.

Dado el siguiente archivo de diseño:

<body>
@yield('content')
</body>

Puede configurar Livewire para referenciarlo usando ->extends() en lugar de ->layout():

public function render()
{
return view('livewire.show-posts')
->extends('layouts.app');
}

Si necesita configurar la @section para que la utilice el componente, también puede hacerlo con el método ->section():

public function render()
{
return view('livewire.show-posts')
->extends('layouts.app')
->section('body');
}

Establecer el título de la página

Asignar títulos de página únicos a cada página de su aplicación es útil tanto para los usuarios como para los motores de búsqueda.

Para establecer un título de página personalizado para un componente de página completa, asegúrese primero de que su archivo de diseño incluye un título dinámico:

<head>
<title>{{ $title ?? 'Page Title' }}</title>
</head>

A continuación, sobre el método render() de su componente Livewire, añada el atributo #[Title] y pásele el título de su página:

<?php
namespace App\Livewire;
use Livewire\Attributes\Title;
use Livewire\Component;
class CreatePost extends Component
{
// ...
#[Title('Create Post')]
public function render()
{
return view('livewire.create-post');
}
}

Esto establecerá el título de la página para el componente CreatePost Livewire. En este ejemplo, el título de la página será “Create Post” cuando el componente sea renderizado.

Si lo prefiere, puede utilizar este atributo sobre la declaración de clase:

<?php
namespace App\Livewire;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Create Post')]
class CreatePost extends Component
{
// ...
}

Si necesita pasar un título dinámico, como un título que utiliza una propiedad del componente, puede utilizar el método fluent ->title() en el método render() del componente:

public function render()
{
return view('livewire.create-post')
->title('Create Post');
}

Configuración de ranuras adicionales del archivo del layout

Si su archivo de layout tiene otros espacios con nombre además de $slot, puede definir su contenido en la vista Blade definiendo <x-slot>s fuera del elemento raíz. Por ejemplo, si desea establecer el idioma de la página para cada componente individualmente, puede añadir una ranura dinámica $lang en la etiqueta HTML de apertura del archivo de diseño:

resources/views/components/layouts/app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', $lang ?? app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ $title ?? 'Page Title' }}</title>
</head>
<body>
{{ $slot }}
</body>
</html>

A continuación, en la vista del componente, defina un elemento <x-slot> fuera del elemento raíz:

<x-slot:lang>en</x-slot> // Este componente está en inglés
<div>
// El contenido en inglés aquí
</div>

Acceso a los parámetros de ruta

Cuando trabajes con Full Page Components, puede que necesite acceder a parámetros de ruta dentro de su componente Livewire.

Para demostrarlo, primero, defina una ruta con un parámetro en su archivo routes/web.php:

use App\Livewire\ShowPost;
Route::get('/posts/{id}', ShowPost::class);

Aquí, hemos definido una ruta con un parámetro id que representa el ID de una entrada.

A continuación, actualice su componente Livewire para aceptar el parámetro de ruta en el método mount():

<?php
namespace App\Livewire;
use App\Models\Post;
use Livewire\Component;
class ShowPost extends Component
{
public Post $post;
public function mount($id)
{
$this->post = Post::findOrFail($id);
}
public function render()
{
return view('livewire.show-post');
}
}

En este ejemplo, como el nombre del parámetro $id coincide con el parámetro de ruta {id}, si se visita la URL /posts/1, Livewire pasará el valor “1” como $id.

Uso de la vinculación(binding) de modelos de ruta La vinculación de modelos de rutas de Laravel te permite resolver automáticamente modelos de Eloquent a partir de parámetros de rutas.

Después de definir una ruta con un parámetro de modelo en su archivo routes/web.php:

use App\Livewire\ShowPost;
Route::get('/posts/{post}', ShowPost::class);

Ahora puede aceptar el parámetro del modelo de ruta a través del método mount() de su componente:

<?php
namespace App\Livewire;
use App\Models\Post;
use Livewire\Component;
class ShowPost extends Component
{
public Post $post;
public function mount(Post $post)
{
$this->post = $post;
}
public function render()
{
return view('livewire.show-post');
}
}

Livewire sabe que usa “route model binding” porque el Post type-hint se añade al parámetro $post en mount().

Como antes, se puede reducir el boilerplate omitiendo el método mount():

<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\Post;
class ShowPost extends Component
{
public Post $post;
public function render()
{
return view('livewire.show-post');
}
}

La propiedad $post se asignará automáticamente al modelo vinculado a través del parámetro {post} de la ruta.

Modificación de la respuesta

En algunos casos, es posible que desee modificar la respuesta y establecer un encabezado de respuesta personalizado. Puedes engancharte al objeto respuesta llamando al método response() en la vista y utilizar un cierre para modificar el objeto respuesta:

<?php
namespace App\Livewire;
use Livewire\Component;
use Illuminate\Http\Response;
class ShowPost extends Component
{
public function render()
{
return view('livewire.show-post')
->response(function(Response $response) {
$response->header('X-Custom-Header', true);
});
}
}

Uso de JavaScript

Hay muchos casos en los que las utilidades incorporadas de Livewire y Alpine no son suficientes para lograr sus objetivos dentro de sus componentes Livewire.

Afortunadamente, Livewire proporciona muchos puntos de extensión y utilidades útiles para interactuar con JavaScript a medida. Puedes aprender de la exhaustiva referencia en la página de documentación de JavaScript. Pero por ahora, aquí hay algunas formas útiles de utilizar su propio JavaScript dentro de sus componentes Livewire.

Ejecutando scripts

Livewire proporciona una útil directiva @script que, al envolver un elemento <script>, ejecutará el JavaScript dado cuando su componente se inicialice en la página.

Aquí hay un ejemplo de un @script simple que usa setInterval() de JavaScript para refrescar su componente cada dos segundos:

@script
<script>
setInterval(() => {
$wire.$refresh()
}, 2000)
</script>
@endscript

Notarás que estamos usando un objeto llamado $wire dentro del <script> para controlar el componente. Livewire automáticamente hace que este objeto esté disponible dentro de cualquier @script. Si no está familiarizado con $wire, puede aprender más sobre $wire en la siguiente documentación:

Carga de assets

Además de @scripts puntuales, Livewire proporciona una útil utilidad @assets para cargar fácilmente cualquier dependencia de script/estilo en la página.

También asegura que los activos proporcionados se cargan sólo una vez por página del navegador, a diferencia de @script, que se ejecuta cada vez que se inicializa una nueva instancia de ese componente Livewire.

Aquí hay un ejemplo del uso de @assets para cargar una librería de selector de fecha llamada Pikaday e inicializarla dentro de su componente usando @script:

<div>
<input type="text" data-picker>
</div>
@assets
<script src="https://cdn.jsdelivr.net/npm/pikaday/pikaday.js" defer></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css">
@endassets
@script
<script>
new Pikaday({ field: $wire.$el.querySelector('[data-picker]') });
</script>
@endscript