> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# ⚡Introductie van Livewire 4 — reactieve UI's bouwen zonder JavaScript

> Hoe je met Livewire 4, het first-party pakket van Laravel, interactieve UI's bouwt zonder JavaScript te schrijven — van installatie tot praktische codevoorbeelden.

## Wat is Livewire?

Wilde je vroeger een dynamische UI bouwen met Laravel, dan kon dat alleen door een JavaScript-framework zoals Vue.js of React te combineren, of door zelf AJAX-requests te schrijven.

**Livewire** is het Laravel-pakket dat dit probleem oplost. Je bouwt reactieve UI's met alleen PHP en Blade. Realtime formuliervalidatie, live zoeken, tellers — functionaliteit waarvoor je vroeger JavaScript nodig had, implementeer je volledig in PHP.

<Info>
  Livewire 4 werkt met Laravel 10 en hoger en PHP 8.1 en hoger. De huidige nieuwste versie is Livewire 4.
</Info>

### Hoe het werkt in het kort

Een Livewire-component is een combinatie van een PHP-klasse op de server en een Blade-template. Klikt een gebruiker op een knop of typt hij in een formulier, dan stuurt Livewire achter de schermen een AJAX-request, voert het PHP uit en werkt het alleen de gewijzigde delen van de pagina bij. Als ontwikkelaar hoef je je van dit mechanisme niets aan te trekken en schrijf je alleen PHP.

***

## Installatie

Voer het volgende commando uit in de rootdirectory van je Laravel-applicatie.

```shell theme={null}
composer require livewire/livewire
```

De automatische pakketdetectie van Laravel is actief, dus extra configuratie is niet nodig.

### Het layoutbestand aanmaken

Gebruik je een component als volledige pagina, dan heb je een layoutbestand nodig. Dat genereer je met het volgende Artisan-commando.

```shell theme={null}
php artisan livewire:layout
```

Er wordt een `resources/views/layouts/app.blade.php` gegenereerd.

```blade theme={null}
<!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 ?? config('app.name') }}</title>

        @vite(['resources/css/app.css', 'resources/js/app.js'])

        @livewireStyles
    </head>
    <body>
        {{ $slot }}

        @livewireScripts
    </body>
</html>
```

`@livewireStyles` en `@livewireScripts` laden automatisch de assets van Livewire en Alpine.js.

***

## Je eerste component

Er is een Artisan-commando om Livewire-componenten te genereren. Laten we een eenvoudige teller maken.

```shell theme={null}
php artisan make:livewire Counter
```

Dit commando genereert een single-file component genaamd `resources/views/components/⚡counter.blade.php`.

<Tip>
  De ⚡ in de bestandsnaam dient om Livewire-componenten in één oogopslag te herkennen. Dat vergroot de zichtbaarheid in je editor. Heb je hem niet nodig, dan kun je hem uitschakelen in de configuratie.
</Tip>

Bewerk het gegenereerde bestand als volgt.

```blade theme={null}
<?php

use Livewire\Component;

new class extends Component {
    public int $count = 0;

    public function increment(): void
    {
        $this->count++;
    }

    public function decrement(): void
    {
        $this->count--;
    }
};
?>

<div>
    <h1>Telling: {{ $count }}</h1>

    <button wire:click="increment">+1</button>
    <button wire:click="decrement">-1</button>
</div>
```

Om dit component in een Blade-template te plaatsen, gebruik je de gewone Blade-componentsyntaxis.

```blade theme={null}
<livewire:counter />
```

Bij elke klik op een knop wordt de telling bijgewerkt zonder paginareload. `wire:click` roept in plaats van JavaScript een PHP-methode aan.

***

## Properties en acties

### Properties — `wire:model`

Met de directive `wire:model` bind je invoerelementen tweerichtings aan de properties van je component.

```blade theme={null}
<?php

use Livewire\Component;

new class extends Component {
    public string $name = '';
    public string $email = '';
};
?>

<div>
    <input type="text" wire:model="name" placeholder="Naam">
    <input type="email" wire:model="email" placeholder="E-mail">

    <p>Hallo {{ $name }} ({{ $email }})</p>
</div>
```

Standaard synchroniseert `wire:model` alleen met de server wanneer een actie wordt uitgevoerd (zoals het verzenden van een formulier). Wil je bij elke invoer synchroniseren, voeg dan de modifier `.live` toe.

| Notatie                | Gedrag                                                                                        |
| ---------------------- | --------------------------------------------------------------------------------------------- |
| `wire:model`           | Synchroniseert alleen bij het uitvoeren van een actie (zoals formulierverzending) (standaard) |
| `wire:model.live`      | Stuurt bij elke invoer een request                                                            |
| `wire:model.blur`      | Synchroniseert bij het verliezen van focus (er vindt geen request plaats)                     |
| `wire:model.live.blur` | Stuurt een request bij het verliezen van focus                                                |

### Acties — `wire:click`, `wire:submit`

`wire:click` koppelt een methode aan het klikevent, `wire:submit` aan het verzendevent van een formulier.

```blade theme={null}
<?php

use Livewire\Component;
use App\Models\Task;

new class extends Component {
    public string $taskName = '';

    public function addTask(): void
    {
        Task::create(['name' => $this->taskName]);
        $this->taskName = '';
    }

    public function render()
    {
        return $this->view([
            'tasks' => Task::latest()->get(),
        ]);
    }
};
?>

<div>
    <form wire:submit="addTask">
        <input type="text" wire:model="taskName" placeholder="Taaknaam">
        <button type="submit">Toevoegen</button>
    </form>

    <ul>
        @foreach ($tasks as $task)
            <li>{{ $task->name }}</li>
        @endforeach
    </ul>
</div>
```

***

## Realtime validatie

In Livewire 4 kun je met het `#[Validate]`-attribute validatieregels rechtstreeks op een property definiëren.

```blade theme={null}
<?php

use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\Post;

new class extends Component {
    #[Validate('required|min:3')]
    public string $title = '';

    #[Validate('required|min:10')]
    public string $content = '';

    public function save(): void
    {
        $this->validate();

        Post::create([
            'title' => $this->title,
            'content' => $this->content,
        ]);

        $this->reset(['title', 'content']);

        session()->flash('message', 'Artikel opgeslagen.');
    }
};
?>

<div>
    @if (session('message'))
        <div>{{ session('message') }}</div>
    @endif

    <form wire:submit="save">
        <div>
            <input type="text" wire:model.live.blur="title" placeholder="Titel">
            @error('title') <span style="color: red;">{{ $message }}</span> @enderror
        </div>

        <div>
            <textarea wire:model.live.blur="content" placeholder="Inhoud"></textarea>
            @error('content') <span style="color: red;">{{ $message }}</span> @enderror
        </div>

        <button type="submit">Opslaan</button>
    </form>
</div>
```

Properties met `#[Validate]` worden bij elke update automatisch gevalideerd. Combineer je dit met `wire:model.live.blur`, dan krijg je een realtime validatie-ervaring waarbij foutmeldingen verschijnen zodra een veld de focus verliest.

<Info>
  `$this->validate()` valideert bij het verzenden van het formulier alle properties in één keer. Het aanbevolen patroon is een tweetrapsaanpak: automatische validatie via `#[Validate]` plus deze aanroep.
</Info>

***

## Lifecycle-hooks

Livewire-componenten hebben een aantal lifecycle-hooks.

| Hook                          | Moment                                                               |
| ----------------------------- | -------------------------------------------------------------------- |
| `mount()`                     | Wanneer het component voor het eerst wordt aangemaakt (eenmalig)     |
| `boot()`                      | Aan het begin van elk request (zowel het eerste als vervolgrequests) |
| `updating($property, $value)` | Vlak voordat een property wordt bijgewerkt                           |
| `updated($property)`          | Direct nadat een property is bijgewerkt                              |
| `rendering()`                 | Vóór het renderen van de view                                        |
| `rendered()`                  | Na het renderen van de view                                          |
| `dehydrate()`                 | Aan het einde van elk request                                        |

### `mount()` — initialisatie

`mount()` gebruik je voor de initialisatie van het component. Het is het alternatief voor een constructor.

```blade theme={null}
<?php

use Illuminate\Support\Facades\Auth;
use Livewire\Component;

new class extends Component {
    public string $name = '';
    public string $email = '';

    public function mount(): void
    {
        $this->name = Auth::user()->name;
        $this->email = Auth::user()->email;
    }
};
?>

<div>
    <p>Naam: {{ $name }}</p>
    <p>E-mail: {{ $email }}</p>
</div>
```

### `updated()` — verwerking na een propertywijziging

Wil je iets doen nadat een property is bijgewerkt, gebruik dan `updated()`. Richt je je op een specifieke property, dan neem je die op in de methodenaam.

```blade theme={null}
<?php

use Livewire\Component;

new class extends Component {
    public string $username = '';

    public function updatedUsername(): void
    {
        $this->username = strtolower($this->username);
    }
};
?>

<div>
    <input type="text" wire:model.live="username">
    <p>Gebruikersnaam: {{ $username }}</p>
</div>
```

Bij elke invoer wordt de tekst automatisch omgezet naar kleine letters.

***

## Integratie met Laravel

### Eloquent-modellen gebruiken

Livewire kan Eloquent-modellen rechtstreeks in properties bewaren.

```blade theme={null}
<?php

use Livewire\Attributes\Validate;
use Livewire\Component;
use App\Models\User;

new class extends Component {
    public User $user;

    public function mount(User $user): void
    {
        $this->user = $user;
    }

    #[Validate('required|min:2')]
    public string $name = '';

    public function save(): void
    {
        $this->validate();
        $this->user->update(['name' => $this->name]);
        session()->flash('message', 'Profiel bijgewerkt.');
    }

    public function render()
    {
        return $this->view();
    }
};
?>

<div>
    @if (session('message'))
        <div>{{ session('message') }}</div>
    @endif

    <form wire:submit="save">
        <input type="text" wire:model="name" placeholder="Naam">
        @error('name') <span style="color: red;">{{ $message }}</span> @enderror
        <button type="submit">Bijwerken</button>
    </form>
</div>
```

### Formulierobjecten

Complexe formulieren kun je uitsplitsen naar formulierobjecten, zodat je component eenvoudig blijft.

```shell theme={null}
php artisan livewire:form PostForm
```

```php theme={null}
namespace App\Livewire\Forms;

use Livewire\Attributes\Validate;
use Livewire\Form;
use App\Models\Post;

class PostForm extends Form
{
    #[Validate('required|min:3')]
    public string $title = '';

    #[Validate('required|min:10')]
    public string $content = '';

    public function store(): void
    {
        Post::create($this->only(['title', 'content']));
    }
}
```

Het formulierobject gebruik je vervolgens vanuit je component.

```blade theme={null}
<?php

use App\Livewire\Forms\PostForm;
use Livewire\Component;

new class extends Component {
    public PostForm $form;

    public function save(): void
    {
        $this->form->validate();
        $this->form->store();
        $this->form->reset();
        session()->flash('message', 'Bericht aangemaakt.');
    }
};
?>

<div>
    <form wire:submit="save">
        <input type="text" wire:model="form.title" placeholder="Titel">
        @error('form.title') <span style="color: red;">{{ $message }}</span> @enderror

        <textarea wire:model="form.content" placeholder="Inhoud"></textarea>
        @error('form.content') <span style="color: red;">{{ $message }}</span> @enderror

        <button type="submit">Plaatsen</button>
    </form>
</div>
```

***

## Conclusie

Een overzicht van de use-cases waarvoor Livewire bijzonder geschikt is.

| Use-case            | Wat Livewire mogelijk maakt                      |
| ------------------- | ------------------------------------------------ |
| Formulierverwerking | Realtime validatie, foutweergave                 |
| Datalijsten         | Live zoeken, sorteren, paginering                |
| Tellers en toggles  | UI-updates zonder paginareload                   |
| Beheerpanelen       | CRUD-bewerkingen met directe Eloquent-integratie |
| Wizardformulieren   | Stapbeheer geïmplementeerd in PHP                |

Elke Laravel-ontwikkelaar die "weleens Blade heeft gebruikt" kan vandaag nog met Livewire aan de slag. De grootste kracht is dat je interactieve UI's realiseert zonder de leercurve van een JavaScript-framework.

Heb je geavanceerde interacties op SPA-niveau nodig, dan past Inertia.js beter, maar voor formulieren, beheerpanelen en datatabellen is Livewire vaak eenvoudiger te implementeren. Probeer het eerst eens met één klein component.

<Card title="Officiële documentatie van Livewire" icon="book-open" href="https://livewire.laravel.com/docs">
  Raadpleeg de officiële documentatie voor alle functies van Livewire (bestandsuploads, paginering, testen, enz.).
</Card>


## Related topics

- [Introductie tot authenticatie](/nl/authentication.md)
- [Frontend](/nl/frontend.md)
- [Een SPA bouwen met Inertia.js](/nl/blog/inertia-introduction.md)
- [Introductie React — de basis voor Inertia × Laravel](/nl/blog/react-introduction.md)
- [Laravel Pulse](/nl/pulse.md)
