Aller au contenu principal

Module 2 – Bases des composants Livewire

Niveau 5.1 – Laravel Livewire


Structure d’un composant Livewire (classe + vue), état (propriétés publiques), actions (wire:click, wire:submit) et liaison des données (wire:model). Le tableau des directives en fin de module sert de référence pour la suite.


Objectif

À la fin de ce module, vous saurez :

  • Générer un composant Livewire et comprendre sa structure : une classe PHP (état + méthodes) et une vue Blade (template).
  • Utiliser les propriétés publiques comme état partagé entre la classe et la vue ; savoir ce qui est hydraté entre les requêtes.
  • Mettre en place le data binding avec wire:model (liaison bidirectionnelle) sur inputs, textareas et selects.
  • Déclencher des actions côté serveur avec wire:click et wire:submit, et comprendre le flux : action → méthode PHP → re-render → mise à jour du DOM.

Nous illustrons tout avec un composant UserSearch (champ de recherche + affichage de la saisie) et un petit formulaire (nom + bouton Enregistrer).


Génération et structure

Pour créer un nouveau composant :

php artisan make:livewire UserSearch

Livewire crée deux fichiers :

FichierRôle
app/Livewire/UserSearch.phpClasse du composant : propriétés publiques (état), méthodes (actions), render().
resources/views/livewire/user-search.blade.phpVue Blade : HTML + directives Livewire (wire:model, wire:click, etc.).

Le nom du composant est dérivé du nom de la classe : UserSearch → composant user-search (kebab-case). Vous l’affichez avec <livewire:user-search /> ou @livewire('user-search').

Règle importante : seules les propriétés publiques de la classe sont sérialisées et envoyées au client, puis réhydratées à chaque requête. Les propriétés protected ou private ne font pas partie de l’état Livewire ; elles sont réinitialisées à chaque requête. Utilisez-les pour des dépendances (injection, services) ou des données temporaires non exposées.


Propriétés publiques = état du composant

Les propriétés publiques sont l’état du composant. Elles sont :

  • Accessibles dans la vue Blade : {{ $query }}, {{ $name }}, etc.
  • Sérialisées lors de l’envoi de la requête AJAX (valeurs envoyées au serveur).
  • Réhydratées côté serveur avant d’exécuter la méthode appelée (ex. save()).
  • Re-sérialisées dans la réponse pour que le client garde le même état (ou le nouvel état après mise à jour).

Types supportés : scalaires (string, int, bool, float), tableaux, objets sérialisables. Les modèles Eloquent peuvent être stockés (Livewire les sérialise par ID et les réhydrate automatiquement). Évitez les closures, ressources, ou objets non sérialisables.

Exemple :

class UserSearch extends Component
{
public string $query = '';

public function render()
{
return view('livewire.user-search');
}
}

Dans la vue, $query est disponible. Si vous liez un input avec wire:model="query", la valeur saisie sera envoyée au serveur et mise à jour dans $query (voir ci-dessous).


Binding : wire:model

wire:model crée une liaison bidirectionnelle entre un champ de formulaire (input, textarea, select) et une propriété publique du composant.

  • Côté client : quand l’utilisateur tape ou change la valeur, Livewire peut envoyer cette valeur au serveur (selon le mode : à chaque frappe, au blur, ou au submit — voir module 3).
  • Côté serveur : la propriété est mise à jour avec la valeur reçue ; puis, si une méthode est appelée (ou après un re-render), la vue est rendue avec la nouvelle valeur. Le DOM est mis à jour.

Syntaxe : wire:model="nomDeLaPropriete". Le nom doit correspondre à une propriété publique de la classe.

Exemple :

<input type="text" wire:model="query" placeholder="Rechercher...">
<p>Vous cherchez : {{ $query }}</p>

Dès que l’utilisateur modifie l’input, Livewire envoie la nouvelle valeur de query au serveur (par défaut à chaque frappe ; en production on préfère souvent wire:model.live.debounce.300ms pour limiter les requêtes). Le serveur met à jour $this->query, re-rend la vue, et le paragraphe « Vous cherchez : … » se met à jour sans rechargement.


Actions : wire:click et wire:submit

Pour exécuter une méthode du composant côté serveur au clic ou à la soumission d’un formulaire :

  • wire:click="nomMethode" : au clic sur l’élément (bouton, lien, div), Livewire envoie une requête et appelle nomMethode() sur la classe.
  • wire:submit="nomMethode" : à la soumission du formulaire, Livewire intercepte l’événement, envoie les champs liés (wire:model) et appelle nomMethode().

Vous pouvez passer des paramètres : wire:click="delete({{ $item->id }})" ou wire:click="setFilter('active')". Les paramètres sont envoyés au serveur et passés à la méthode.

Exemple :

<button wire:click="increment">+1</button>

<form wire:submit="save">
<input type="text" wire:model="name">
<button type="submit">Enregistrer</button>
</form>

Dans la classe : méthodes increment() et save(). Lors de save(), les propriétés liées par wire:model (ex. $name) sont déjà à jour quand la méthode s’exécute, car Livewire met à jour l’état avant d’appeler la méthode.


Exemple complet : UserSearch (recherche en direct)

Composant qui affiche un champ de recherche et la valeur saisie en dessous.

Classe app/Livewire/UserSearch.php

<?php

namespace App\Livewire;

use Livewire\Component;

class UserSearch extends Component
{
public string $query = '';

public function render()
{
return view('livewire.user-search');
}
}

Vue resources/views/livewire/user-search.blade.php

<div>
<label for="search">Rechercher un utilisateur</label>
<input type="text" id="search" wire:model="query" placeholder="Nom ou email...">
<p>Vous cherchez : <strong>{{ $query ?: '(vide)' }}</strong></p>
</div>

Comportement : à chaque modification de l’input (selon le mode de wire:model), la valeur est envoyée au serveur, $query est mise à jour, la vue est re-rendue, et le texte « Vous cherchez : … » se met à jour. Pour limiter les requêtes en production, préférez wire:model.live.debounce.300ms="query" (voir module 3).


Exemple complet : formulaire simple (nom + sauvegarde)

Un formulaire avec un champ nom et un bouton ; au clic sur « Enregistrer », une méthode save() est appelée (vous pourrez y ajouter la validation et l’enregistrement en BDD au module 4).

Classe app/Livewire/SimpleForm.php

<?php

namespace App\Livewire;

use Livewire\Component;

class SimpleForm extends Component
{
public string $name = '';

public function save(): void
{
// Pour l’instant on ne fait qu’afficher ; au module 4 on ajoutera validate() et User::create()
session()->flash('message', 'Nom enregistré : ' . $this->name);
}

public function render()
{
return view('livewire.simple-form');
}
}

Vue resources/views/livewire/simple-form.blade.php

<div>
<form wire:submit="save">
<label for="name">Nom</label>
<input type="text" id="name" wire:model="name" required>
<button type="submit">Enregistrer</button>
</form>
@if (session('message'))
<p class="text-green-600">{{ session('message') }}</p>
@endif
</div>
  • wire:model="name" : la valeur de l’input est stockée dans $name. Lors de la soumission, save() est appelée ; $this->name contient déjà la valeur saisie.
  • session()->flash('message', ...) : après la redirection ou le re-render, le message est affiché une fois. En Livewire, comme il n’y a pas de redirection par défaut, le re-render du composant affiche le message tant que la session le contient.

Exercices proposés

  • Compteur étendu : mêmes bases que le module 1, mais ajoutez des boutons -1 et Reset (méthode qui remet $count à 0). Utilisez wire:click="decrement" et wire:click="reset".
  • Formulaire « prénom + nom » : deux propriétés $firstName et $lastName, un formulaire avec wire:submit="save". Dans save(), affichez un message flash avec le nom complet. Vérifiez que les deux champs sont bien mis à jour dans l’état avant l’appel à save().

À retenir

  • Un composant Livewire = classe PHP (état + méthodes) + vue Blade (template). Génération : php artisan make:livewire NomDuComposant.
  • Propriétés publiques = état du composant ; sérialisées/réhydratées entre les requêtes ; accessibles dans la vue avec {{ $nom }}.
  • wire:model="propriete" = liaison bidirectionnelle entre un input/textarea/select et une propriété publique. La valeur est envoyée au serveur et la vue est mise à jour après re-render.
  • wire:click="methode" et wire:submit="methode" = appels de méthodes côté serveur ; après exécution, render() est relancé et le DOM est mis à jour (sans rechargement complet).
  • Passer des paramètres : wire:click="methode({{ $id }})" ou wire:click="setFilter('actif')".

Directives Livewire en un coup d’œil

DirectiveRôleExemple
wire:model="prop"Lie un input/textarea/select à une propriété (bidirectionnel).wire:model="name"
wire:model.lazyMise à jour au blur.Réduire les requêtes sur les champs texte.
wire:model.deferMise à jour uniquement à la prochaine action (clic, submit).Formulaires multi-champs.
wire:click="methode"Appelle une méthode publique au clic.wire:click="save"
wire:click="methode(42)"Appelle avec des paramètres.wire:click="delete({{ $item->id }})"
wire:submit="methode"Appelle une méthode à la soumission du formulaire.wire:submit="register"
wire:key="unique-id"Clé unique pour les éléments de liste (morphing correct).wire:key="item-{{ $item->id }}" (module 10)
wire:loadingAffiche le contenu pendant une requête.Indicateur de chargement (module 5).

Les modificateurs .lazy, .debounce, .defer et .live sur wire:model sont détaillés au module 3.


Erreurs fréquentes (débutant)

  • Méthode non trouvée : vérifier que la méthode est publique et que le nom dans wire:click ou wire:submit correspond exactement (sensible à la casse).
  • Propriété non affichée dans la vue : seules les propriétés publiques sont accessibles dans Blade. Une propriété protected ou private ne sera pas disponible dans {{ $maProp }}.
  • Valeur du champ perdue après une action : si vous n’avez pas lié l’input avec wire:model, la valeur ne fait pas partie de l’état ; elle est perdue au prochain re-render. Toujours lier les champs de formulaire à une propriété publique.
  • Paramètres passés à wire:click : pour un entier, écrire wire:click="delete({{ $id }})" (sans guillemets autour de $id). Pour une chaîne : wire:click="setStatus('active')" (guillemets autour de la valeur).

Approfondissement

  • Valeurs calculées (non stockées en propriété) : pour afficher une valeur dérivée (ex. nom complet à partir de $firstName et $lastName) sans en faire une propriété publique, passez-la dans render() : return view('livewire.user-card', ['fullName' => $this->firstName . ' ' . $this->lastName]);. Dans la vue, utilisez {{ $fullName }}. Ainsi vous ne surchargez pas l’état sérialisé avec des données redondantes.
  • wire:key : dans une boucle @foreach, toujours ajouter wire:key="unique-id" sur l’élément racine de chaque item (ex. <div wire:key="user-{{ $user->id }}">) pour que Livewire puisse associer correctement les nœuds DOM lors du morphing. Sinon, en cas d’ajout/suppression/réordre, les valeurs des inputs peuvent être réattribuées aux mauvais éléments (module 10).
  • wire:ignore : sur un conteneur, indique à Livewire de ne pas modifier ce bloc lors du morphing. Utile quand une librairie JavaScript (éditeur WYSIWYG, graphique) gère son propre DOM et que Livewire ne doit pas l’écraser.
  • Composants imbriqués : vous pouvez inclure un composant Livewire dans la vue d’un autre : <livewire:user-avatar :user-id="$user->id" />. Chaque composant a son propre cycle de vie et son propre état. Pour communiquer entre parent et enfant, utilisez les événements (module 3 : $dispatch et #[On]).

À retenir

  • Un composant Livewire = classe PHP (état + méthodes) + vue Blade (template). Génération : php artisan make:livewire NomDuComposant. Nom du composant = kebab-case de la classe (ex. UserSearch → user-search).
  • Propriétés publiques = état du composant ; sérialisées/réhydratées entre les requêtes ; accessibles dans la vue avec {{ $nom }}. protected / private = pas dans l’état Livewire.
  • wire:model="propriete" = liaison bidirectionnelle ; wire:click="methode" et wire:submit="methode" = appels côté serveur ; après exécution, render() est relancé et le DOM est mis à jour.
  • Passer des paramètres : wire:click="methode({{ $id }})" ou wire:click="setFilter('actif')". Dans la classe, la méthode reçoit les arguments dans l’ordre.

Dans le prochain module, nous voyons les modes de binding (lazy, debounce, defer) pour contrôler quand les valeurs sont envoyées au serveur, et la communication entre composants (événements $dispatch, listeners #[On]).