Laravel Livewire 3 en 2026 : Applications Réactives et Questions d'Entretien
Maîtrisez Laravel Livewire 3 avec ce guide complet sur les composants réactifs, l'intégration Alpine.js, la validation en temps réel et les questions d'entretien technique.

Laravel Livewire 3 révolutionne la création d'interfaces dynamiques et réactives pour les développeurs PHP, sans nécessiter d'écrire une seule ligne de JavaScript. Cette évolution majeure du framework apporte une intégration native avec Alpine.js, des performances optimisées grâce au morphing DOM, et une syntaxe de composants plus élégante qui rend le développement d'applications temps réel naturel au sein de l'écosystème Laravel.
Livewire 3 utilise Alpine.js en interne et nécessite les directives @livewireStyles et @livewireScripts dans le layout. La directive wire:model utilise désormais le binding différé par défaut — utilisez wire:model.live pour les mises à jour en temps réel.
Architecture Livewire 3 et Binding Réactif
Livewire repose sur un concept simple mais puissant : des composants PHP qui se re-rendent côté serveur et envoient des différences HTML au navigateur. Chaque composant maintient son état entre les requêtes grâce à un mécanisme de sérialisation qui préserve les valeurs des propriétés.
L'architecture diffère fondamentalement de la réactivité basée sur JavaScript. Au lieu de maintenir un DOM virtuel côté client, Livewire sérialise l'état du composant, l'envoie avec chaque requête, et effectue le morphing du DOM en fonction de la réponse serveur. Cette approche conserve la logique métier en PHP tout en offrant l'expérience réactive attendue par les utilisateurs.
<?php
namespace App\Livewire;
use App\Models\User;
use Livewire\Component;
use Livewire\WithPagination;
use Livewire\Attributes\Url;
class SearchUsers extends Component
{
use WithPagination;
#[Url] // Synchronise la propriété avec les paramètres URL
public string $search = '';
#[Url]
public string $role = '';
public function updatedSearch(): void
{
// Réinitialise la pagination lors d'un changement de recherche
$this->resetPage();
}
public function render()
{
return view('livewire.search-users', [
'users' => User::query()
->when($this->search, fn($q) => $q->where('name', 'like', "%{$this->search}%"))
->when($this->role, fn($q) => $q->where('role', $this->role))
->paginate(10),
]);
}
}L'attribut #[Url] synchronise automatiquement les propriétés avec les paramètres de requête URL, permettant des vues filtrées partageables sans code supplémentaire. Le hook de cycle de vie updatedSearch se déclenche lorsque la propriété search change, réinitialisant la pagination à la première page.
Syntaxe des Composants Livewire 3 avec les Attributs PHP 8
Livewire 3 adopte les attributs PHP 8 pour la configuration, remplaçant l'approche précédente basée sur les méthodes. Ce style déclaratif améliore la lisibilité et réduit le code répétitif dans les composants.
<?php
namespace App\Livewire;
use App\Models\Post;
use Livewire\Component;
use Livewire\Attributes\Rule;
use Livewire\Attributes\Locked;
use Livewire\Attributes\Computed;
class CreatePost extends Component
{
#[Locked] // Ne peut pas être modifié depuis le frontend
public int $userId;
#[Rule('required|min:5|max:200')]
public string $title = '';
#[Rule('required|min:50')]
public string $content = '';
#[Rule('nullable|array')]
public array $tags = [];
public function mount(): void
{
$this->userId = auth()->id();
}
#[Computed]
public function wordCount(): int
{
return str_word_count($this->content);
}
public function save(): void
{
$validated = $this->validate();
Post::create([
'user_id' => $this->userId,
...$validated,
]);
$this->reset(['title', 'content', 'tags']);
$this->dispatch('post-created');
}
public function render()
{
return view('livewire.create-post');
}
}L'attribut #[Locked] empêche la manipulation frontend des propriétés sensibles — essentiel pour la sécurité lors du passage d'identifiants ou de permissions. Les attributs #[Rule] définissent la validation en ligne, tandis que #[Computed] met en cache les calculs coûteux jusqu'à ce que les dépendances changent.
Utilisez toujours #[Locked] pour les identifiants utilisateur, les indicateurs de permission et toute donnée qui ne doit pas être falsifiée depuis le navigateur. Livewire transmet l'état du composant dans chaque requête, rendant les propriétés non protégées vulnérables à la modification.
Validation de Formulaire en Temps Réel et Retour Utilisateur
Livewire excelle dans la fourniture de retours de validation immédiats sans rechargement de page. Le framework valide les propriétés pendant la saisie, affichant les erreurs à côté des champs de formulaire en temps réel.
<?php
namespace App\Livewire;
use App\Models\User;
use Livewire\Component;
use Livewire\Attributes\Rule;
use Livewire\Attributes\Validate;
use Illuminate\Validation\Rules\Password;
class RegistrationForm extends Component
{
#[Rule('required|email|unique:users,email')]
public string $email = '';
#[Rule('required|min:2|max:50')]
public string $name = '';
public string $password = '';
public string $passwordConfirmation = '';
public function rules(): array
{
return [
'password' => [
'required',
'confirmed',
Password::min(8)->mixedCase()->numbers(),
],
];
}
public function updated(string $property): void
{
// Valide une seule propriété lors du changement
$this->validateOnly($property);
}
public function register(): void
{
$validated = $this->validate();
$user = User::create([
'email' => $validated['email'],
'name' => $validated['name'],
'password' => bcrypt($validated['password']),
]);
auth()->login($user);
$this->redirect('/dashboard');
}
public function render()
{
return view('livewire.registration-form');
}
}Le template Blade correspondant utilise wire:model.blur pour déclencher la validation lorsque l'utilisateur quitte un champ, équilibrant réactivité et charge serveur :
{{-- resources/views/livewire/registration-form.blade.php --}}
<form wire:submit="register" class="space-y-4">
<div>
<label for="email" class="block text-sm font-medium">Email</label>
<input
wire:model.blur="email"
type="email"
id="email"
class="mt-1 block w-full rounded-md border-gray-300"
>
@error('email')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<div>
<label for="password" class="block text-sm font-medium">Mot de passe</label>
<input
wire:model.blur="password"
type="password"
id="password"
class="mt-1 block w-full rounded-md border-gray-300"
>
@error('password')
<p class="mt-1 text-sm text-red-600">{{ $message }}</p>
@enderror
</div>
<div>
<label for="passwordConfirmation" class="block text-sm font-medium">Confirmer le mot de passe</label>
<input
wire:model.blur="passwordConfirmation"
type="password"
id="passwordConfirmation"
class="mt-1 block w-full rounded-md border-gray-300"
>
</div>
<button
type="submit"
class="w-full bg-indigo-600 text-white py-2 px-4 rounded-md"
wire:loading.attr="disabled"
>
<span wire:loading.remove>S'inscrire</span>
<span wire:loading>Traitement...</span>
</button>
</form>Ce pattern démontre les forces de Livewire : logique de validation côté serveur avec réactivité côté client, états de chargement sans JavaScript, et séparation nette entre la logique du composant et sa présentation.
Communication Parent-Enfant avec les Événements
Les interfaces complexes nécessitent souvent plusieurs composants Livewire qui communiquent entre eux. Livewire 3 fournit un système d'événements raffiné à cet effet, utilisant le pattern dispatch et l'attribut #[On].
<?php
namespace App\Livewire;
use App\Models\Task;
use Livewire\Component;
use Livewire\Attributes\On;
class TaskBoard extends Component
{
public array $columns = ['todo', 'in_progress', 'done'];
#[On('task-moved')]
public function handleTaskMoved(int $taskId, string $newStatus): void
{
Task::where('id', $taskId)->update(['status' => $newStatus]);
}
#[On('task-created')]
public function refreshBoard(): void
{
// Le composant se re-rend automatiquement
}
public function render()
{
return view('livewire.task-board', [
'tasks' => Task::all()->groupBy('status'),
]);
}
}<?php
namespace App\Livewire;
use App\Models\Task;
use Livewire\Component;
class TaskCard extends Component
{
public Task $task;
public function moveToStatus(string $status): void
{
$this->dispatch('task-moved', taskId: $this->task->id, newStatus: $status);
}
public function render()
{
return view('livewire.task-card');
}
}Les événements remontent par défaut dans la hiérarchie des composants. Pour la communication entre composants en dehors de la relation parent-enfant, les événements peuvent cibler des composants spécifiques en utilisant $this->dispatch('event-name')->to(ComponentClass::class).
Prêt à réussir tes entretiens Laravel ?
Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.
Intégration Alpine.js pour l'Interactivité Côté Client
Livewire 3 intègre Alpine.js nativement, permettant des patterns hybrides où certaines interactions restent côté client tandis que d'autres font l'aller-retour vers le serveur. Cette combinaison réduit la charge serveur pour les simples bascules d'interface tout en préservant le modèle côté serveur de Livewire pour la logique complexe.
{{-- resources/views/livewire/notification-dropdown.blade.php --}}
<div
x-data="{
open: false,
unreadCount: @entangle('unreadCount')
}"
class="relative"
>
<button @click="open = !open" class="relative p-2">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6 6 0 10-12 0v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9" />
</svg>
<span
x-show="unreadCount > 0"
x-text="unreadCount"
class="absolute -top-1 -right-1 bg-red-500 text-white text-xs rounded-full w-5 h-5 flex items-center justify-center"
></span>
</button>
<div
x-show="open"
@click.outside="open = false"
x-transition
class="absolute right-0 mt-2 w-80 bg-white rounded-lg shadow-lg"
>
@foreach($notifications as $notification)
<div
wire:click="markAsRead({{ $notification->id }})"
class="p-4 border-b hover:bg-gray-50 cursor-pointer"
>
<p class="font-medium">{{ $notification->title }}</p>
<p class="text-sm text-gray-600">{{ $notification->message }}</p>
</div>
@endforeach
</div>
</div>La directive @entangle crée un binding bidirectionnel entre l'état Alpine.js et les propriétés Livewire. Les modifications de unreadCount dans Alpine ou Livewire se synchronisent automatiquement, permettant des mises à jour optimistes de l'interface tout en maintenant l'autorité du serveur.
Upload de Fichiers avec Suivi de Progression
Livewire fournit la gestion des uploads de fichiers avec suivi de progression intégré, validation et stockage temporaire. Le trait WithFileUploads ajoute toutes les fonctionnalités nécessaires à n'importe quel composant.
<?php
namespace App\Livewire;
use Livewire\Component;
use Livewire\WithFileUploads;
use Livewire\Attributes\Rule;
use Illuminate\Support\Facades\Storage;
class DocumentUploader extends Component
{
use WithFileUploads;
#[Rule('required|file|mimes:pdf,docx|max:10240')] // 10MB max
public $document;
public ?string $uploadedPath = null;
public function updatedDocument(): void
{
$this->validate();
}
public function save(): void
{
$this->validate();
$this->uploadedPath = $this->document->store('documents', 'public');
$this->dispatch('document-uploaded', path: $this->uploadedPath);
$this->reset('document');
}
public function render()
{
return view('livewire.document-uploader');
}
}{{-- resources/views/livewire/document-uploader.blade.php --}}
<div class="space-y-4">
<div
x-data="{ uploading: false, progress: 0 }"
x-on:livewire-upload-start="uploading = true"
x-on:livewire-upload-finish="uploading = false; progress = 0"
x-on:livewire-upload-error="uploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress"
>
<input
type="file"
wire:model="document"
accept=".pdf,.docx"
class="block w-full text-sm text-gray-500 file:mr-4 file:py-2 file:px-4 file:rounded-md file:border-0 file:bg-indigo-50 file:text-indigo-700"
>
<div x-show="uploading" class="mt-2">
<div class="bg-gray-200 rounded-full h-2">
<div
class="bg-indigo-600 h-2 rounded-full transition-all duration-300"
:style="'width: ' + progress + '%'"
></div>
</div>
<p class="text-sm text-gray-600 mt-1" x-text="'Téléchargement: ' + progress + '%'"></p>
</div>
</div>
@error('document')
<p class="text-sm text-red-600">{{ $message }}</p>
@enderror
@if($document)
<div class="flex items-center justify-between p-3 bg-gray-50 rounded-lg">
<span class="text-sm">{{ $document->getClientOriginalName() }}</span>
<button wire:click="save" class="bg-indigo-600 text-white px-4 py-2 rounded-md text-sm">
Télécharger
</button>
</div>
@endif
</div>Le template combine Alpine.js pour la visualisation de progression côté client avec les événements d'upload de Livewire. Les fichiers sont d'abord téléchargés dans un stockage temporaire, permettant l'aperçu et la validation avant le stockage final.
Questions d'Entretien pour Développeurs Livewire 3
Les entretiens techniques explorent souvent la compréhension de l'architecture de Livewire, son modèle de sécurité et ses caractéristiques de performance. Les questions suivantes apparaissent fréquemment lors du recrutement de développeurs Laravel avec une expérience Livewire.
Les recruteurs évaluent trois domaines principaux : la compréhension du cycle de vie des requêtes Livewire, la sensibilisation à la sécurité concernant les propriétés publiques, et la capacité à optimiser la performance des composants. Démontrer une connaissance de quand NE PAS utiliser Livewire compte autant que savoir l'utiliser.
Comment Livewire maintient-il l'état du composant entre les requêtes ?
Livewire sérialise toutes les propriétés publiques dans un payload qui voyage avec chaque requête. L'état du composant est encodé, signé pour empêcher la falsification, et envoyé au navigateur. Lors des interactions suivantes, ce payload retourne au serveur où Livewire reconstruit l'instance du composant avant de traiter l'action.
Quels problèmes de sécurité existent avec les propriétés publiques Livewire, et comment Livewire les résout-il ?
Les propriétés publiques sont vulnérables car elles sont incluses dans le payload sérialisé envoyé au navigateur. Des utilisateurs malveillants pourraient modifier ce payload avant de le renvoyer. Livewire résout ce problème grâce à la vérification des checksums — toute falsification fait échouer la requête. De plus, l'attribut #[Locked] marque les propriétés comme côté serveur uniquement, les empêchant d'être modifiées via le frontend même si les checksums étaient compromis.
Expliquez la différence entre wire:model, wire:model.live et wire:model.blur.
Dans Livewire 3, wire:model utilise le binding différé par défaut — la propriété ne se met à jour que lorsqu'une action se déclenche (comme la soumission du formulaire). wire:model.live met à jour la propriété à chaque changement d'entrée, déclenchant un aller-retour serveur à chaque frappe. wire:model.blur se met à jour lorsque l'élément perd le focus, équilibrant réactivité et charge serveur réduite. Le modificateur .debounce ajoute un délai aux mises à jour live : wire:model.live.debounce.500ms.
Quand un développeur devrait-il choisir Livewire plutôt qu'Inertia.js ou un framework JavaScript ?
Livewire convient le mieux lorsque l'équipe a une forte expertise PHP mais une expérience JavaScript limitée, lorsque les exigences SEO favorisent le contenu rendu côté serveur, ou lorsque l'application implique des formulaires complexes avec validation côté serveur. Inertia.js ou les frameworks JavaScript conviennent mieux aux tableaux de bord hautement interactifs avec un état côté client complexe, aux applications nécessitant des fonctionnalités hors ligne, ou aux équipes avec une expertise JavaScript qui préfèrent le modèle mental SPA.
Comment optimiser les composants Livewire pour la performance ?
Les optimisations clés incluent : utiliser wire:model.blur au lieu de wire:model.live pour réduire les requêtes, implémenter #[Computed] pour les calculs coûteux afin d'activer le cache, charger paresseusement les composants avec wire:init pour améliorer les performances de rendu initial, utiliser la pagination pour limiter les données envoyées par requête, et éviter les re-rendus inutiles en délimitant les propriétés réactives. Pour les listes, l'attribut wire:key aide Livewire à suivre efficacement les éléments pendant le morphing.
Tester Efficacement les Composants Livewire
Livewire fournit une API de test fluide qui s'intègre au framework de test Laravel. Les tests peuvent simuler les interactions utilisateur, vérifier l'état du composant et contrôler la sortie DOM.
<?php
namespace Tests\Feature\Livewire;
use App\Livewire\SearchUsers;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Tests\TestCase;
class SearchUsersTest extends TestCase
{
use RefreshDatabase;
public function test_can_search_users_by_name(): void
{
User::factory()->create(['name' => 'John Doe', 'role' => 'admin']);
User::factory()->create(['name' => 'Jane Smith', 'role' => 'user']);
Livewire::test(SearchUsers::class)
->set('search', 'John')
->assertSee('John Doe')
->assertDontSee('Jane Smith');
}
public function test_can_filter_by_role(): void
{
User::factory()->create(['name' => 'Admin User', 'role' => 'admin']);
User::factory()->create(['name' => 'Regular User', 'role' => 'user']);
Livewire::test(SearchUsers::class)
->set('role', 'admin')
->assertSee('Admin User')
->assertDontSee('Regular User');
}
public function test_pagination_resets_on_search_change(): void
{
User::factory()->count(25)->create();
Livewire::test(SearchUsers::class)
->call('gotoPage', 2)
->assertSet('paginators.page', 2)
->set('search', 'test')
->assertSet('paginators.page', 1);
}
public function test_url_reflects_search_parameters(): void
{
Livewire::withQueryParams(['search' => 'existing'])
->test(SearchUsers::class)
->assertSet('search', 'existing');
}
}La suite de tests couvre les fonctionnalités, la gestion de l'état et la synchronisation URL.
Conclusion
- Livewire 3 permet des interfaces réactives en PHP pur grâce au rendu côté serveur et au morphing DOM, éliminant le besoin de frameworks JavaScript séparés dans de nombreuses applications Laravel
- Les attributs PHP 8 (
#[Rule],#[Locked],#[Computed],#[Url]) fournissent une configuration déclarative qui améliore la lisibilité du code et la sécurité - L'intégration native d'Alpine.js permet des patterns hybrides où les interactions simples restent côté client tandis que la logique complexe demeure sur le serveur
- La sécurité nécessite une attention particulière : utiliser
#[Locked]pour les propriétés sensibles et comprendre que les propriétés publiques voyagent dans chaque payload de requête - L'optimisation des performances se concentre sur la réduction des allers-retours grâce aux modificateurs appropriés de
wire:modelet l'implémentation de propriétés computed pour les opérations coûteuses - Les questions d'entretien se concentrent sur la compréhension de l'architecture, la sensibilisation à la sécurité et savoir quand des approches alternatives (Inertia.js, SPAs) conviennent mieux aux exigences
Passe à la pratique !
Teste tes connaissances avec nos simulateurs d'entretien et tests techniques.
Tags
Partager
Articles similaires

Tests Laravel en 2026 : Pest, Mocking et Questions d'Entretien Technique
Guide complet des tests Laravel avec Pest en 2026 : tests unitaires, tests fonctionnels, mocking de facades, tests d'architecture, mutation testing et questions d'entretien technique pour developpeurs PHP.

Laravel 12 en 2026 : nouvelles fonctionnalités, Starter Kits et questions d'entretien
Découvrez les nouveautés de Laravel 12 en 2026 : Starter Kits redessinés avec React 19 et WorkOS AuthKit, guide de migration depuis Laravel 11, et questions d'entretien technique essentielles.

Laravel Middleware en profondeur : Authentification, Rate Limiting et Middleware personnalisé
Exploration complète des middleware Laravel avec des exemples pratiques : gardes d'authentification, limitation de débit avec throttle, création de middleware personnalisé et patterns avancés pour les applications en production.