[ Livewire · Dokumentácia ]

Dokumentácia Livewire 4

Kompletná dokumentácia k Livewire 4: jednosúborové komponenty, ostrovy s nezávislým vykresľovaním, sloty, vstavaný drag and drop a klientske direktívy — s vyznačením rozdielov oproti verzii 3.

  • 4.x · Aktuálna
  • Laravel 11 / 12
  • PHP 8.2+
  • 26 kapitol
  • 40 min čítania

1. Čo mení Livewire 4

Livewire 4 je najväčšie vydanie v histórii frameworku. Samotný model komponentu sa nezmenil — PHP trieda a Blade šablóna, stav na serveri, HTML po drôte — no takmer všetko okolo neho sa posunulo: kde komponenty žijú, ako sa píšu a akú časť stránky zasiahne jedna aktualizácia.

Päť najdôležitejších vecí

NovinkaČo prináša
Jednosúborové komponenty Trieda aj značkovanie žijú v jednom súbore .blade.php. Žiadne preskakovanie medzi dvoma priečinkami kvôli dvadsaťriadkovému komponentu.
Ostrovy Izolované oblasti vnútri komponentu, ktoré sa prekresľujú samostatne. Tikajúce počítadlo tržieb už znova nespúšťa dotazy celého dashboardu.
Sloty Rodič vkladá značkovanie do potomka — vyhodnocuje sa v kontexte rodiča, takže wire:click v slote volá metódu rodiča.
Optimistické UI wire:show, wire:text, wire:bind aktualizujú DOM okamžite na klientovi, bez cesty na server.
Drag and drop wire:sort je zabudovaný. Žiadny SortableJS, žiadny lepiaci kód.

Je to prepísanie aplikácie?

Nie. Livewire 4 si zachováva vysokú spätnú kompatibilitu: triedne komponenty fungujú ďalej. Jednosúborový formát je predvolený pre nové komponenty, nie nútená migrácia. Existuje sada nekompatibilných zmien, ktoré si oplatí prečítať pred upgradom — sú zhrnuté v porovnaní Livewire 3 a 4 a oficiálna dokumentácia k upgradu je smerodajný zoznam.

Prichádzate z Livewire 3? Skutočná novinka je v kapitolách 3, 6, 10 a 11 — jednosúborové komponenty, nová sémantika wire:model, ostrovy a sloty. Zvyšok modelu komponentu bude pôsobiť známo.

2. Inštalácia a požiadavky

Bash
composer require livewire/livewire:^4.0

php artisan optimize:clear

Ako v tretej verzii sa assety vkladajú automaticky. @livewireStyles a @livewireScripts treba umiestniť ručne len pri neštandardnom layoute alebo prísnej Content Security Policy.

Endpointy Livewire sa zmenili. URL aktualizácií teraz obsahujú hash: /livewire/ sa stalo /livewire-{hash}/. Ak máte pravidlá firewallu, výnimky WAF, obchádzky CDN alebo location bloky v nginxe naviazané na doslovnú cestu /livewire/, treba ich rozšíriť na nový tvar — inak bude aplikácia v produkcii vyzerať pokazene, hoci na notebooku funguje bezchybne.

Publikovanie konfigurácie

Bash
php artisan livewire:publish --config

Nastavenia, ktoré sú vo štvrtej verzii nové alebo premenované:

NastavenieÚčel
component_locationsPriečinky, v ktorých sa hľadajú komponenty. Predvolene resources/views/components a resources/views/livewire.
component_namespacesPomenované korene komponentov, napr. pages::.
component_layoutVo v3 layout. Používa namespace layouts::.
component_placeholderVo v3 lazy_placeholder.
make_commandUrčuje, čo generuje make:livewire: jednosúborový alebo triedny komponent.
smart_wire_keysTeraz predvolene true.
csp_safeVytvorí build, ktorý vyhovuje prísnejším Content Security Policy.

Voľba predvoleného štýlu komponentov

config/livewire.php
// Naďalej generovať triedne komponenty namiesto jednosúborových
'make_command' => [
    'type' => 'class',
],

3. Jednosúborové komponenty

Hlavná zmena v každodennej práci. Komponent je teraz jeden Blade súbor, ktorý začína PHP blokom s anonymnou triedou a pokračuje značkovaním.

Bash
php artisan make:livewire post.create
# resources/views/components/post/⚡create.blade.php
resources/views/components/post/⚡create.blade.php
<?php

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

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

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

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

        Post::create([
            'title' => $this->title,
            'body'  => $this->body,
            'user_id' => auth()->id(),
        ]);

        $this->reset();

        $this->dispatch('notify', message: 'Post created');
    }
};

?>

<div>
    <form wire:submit="save">
        <input type="text" wire:model="title" placeholder="Title">
        @error('title') <span class="error">{{ $message }}</span> @enderror

        <textarea wire:model="body" placeholder="Body"></textarea>
        @error('body') <span class="error">{{ $message }}</span> @enderror

        <button type="submit">Save post</button>
    </form>
</div>

Verejné vlastnosti sú v značkovaní dostupné ako bežné premenné — {{ $title }} funguje rovnako ako v samostatnom súbore šablóny.

O tom emoji

Predvolený názov súboru nesie predponu ⚡. Je to vizuálny znak, ktorý odlišuje Livewire komponenty od bežných Blade komponentov v tom istom priečinku, a je voliteľný — v config/livewire.php sa dá vypnúť, ak vaše nástroje, terminál alebo tím uprednostňujú obyčajné názvy.

Viacsúborové komponenty

Keď komponent prerastie pohodlnú veľkosť jedného súboru, vygenerujte ho ako viacsúborový komponent a trieda, šablóna a test budú opäť oddelené.

Bash
php artisan make:livewire post.create --mfc

Triedne komponenty fungujú ďalej

app/Livewire/CreatePost.php
<?php

namespace App\Livewire;

use Livewire\Component;

class CreatePost extends Component
{
    public string $title = '';

    public function render()
    {
        return view('livewire.create-post');
    }
}
Čo si vybrať. Jednosúborový formát vyhráva pri malých a stredných komponentoch — formulár, riadok tabuľky, widget. Po triednom alebo viacsúborovom siahnite, keď trieda nesie skutočnú logiku, má veľa závislostí alebo keď má váš tím zaužívané konvencie okolo app/Livewire.

4. Umiestnenie, pomenovanie a namespace

Livewire komponenty už predvolene nežijú vo vlastnom izolovanom priečinku resources/views/livewire; sedia vedľa ostatných Blade komponentov.

Štruktúra priečinkov
resources/views/
├── components/
│   ├── ⚡counter.blade.php              → <livewire:counter />
│   ├── post/
│   │   ├── ⚡create.blade.php           → <livewire:post.create />
│   │   └── ⚡index.blade.php            → <livewire:post.index />
│   └── button.blade.php                 (a plain Blade component)
└── pages/
    └── ⚡dashboard.blade.php            → <livewire:pages::dashboard />

Vykresľovanie

Blade
{{-- Podľa mena --}}
<livewire:counter />

{{-- Vnorené priečinky bodkou --}}
<livewire:post.create />

{{-- S namespace --}}
<livewire:pages::post.create />

{{-- S props --}}
<livewire:post.create :title="$initialTitle" :author="$user" />
Tagy komponentov musia byť uzavreté. Vo v4 sa neuzavretý <livewire:some-component> jednoducho nevykreslí — bez chyby, bez výstupu. Vždy samouzatvárajte: <livewire:some-component />. Toto je najčastejšie prekvapenie pri prenose Blade súborov z v3.

Smerovanie na komponent

Celostránkové komponenty majú vlastné makro routy. Starý zápis Route::get('/dashboard', Dashboard::class) nahrádza:

routes/web.php
use App\Livewire\Dashboard;

// Podľa triedy
Route::livewire('/dashboard', Dashboard::class);

// Podľa mena komponentu — bežná voľba pre komponenty založené na šablóne
Route::livewire('/dashboard', 'pages::dashboard')
    ->middleware('auth')
    ->name('dashboard');

Layouty

config/livewire.php
'component_layout' => 'layouts::app',
PHP
use Livewire\Attributes\Layout;
use Livewire\Attributes\Title;

new class extends Component {
    #[Layout('layouts::app')]
    #[Title('Dashboard')]
    public function render() { /* … */ }
};

5. Vlastnosti a props

Verejné vlastnosti sú stále stavom komponentu, stále sa medzi požiadavkami serializujú do snapshotu a stále platia rovnaké obmedzenia typov: skaláry, polia skalárov, Eloquent modely a kolekcie, Carbon, enumy.

PHP
new class extends Component {
    public string $name = '';
    public ?int $age = null;
    public array $tags = [];
    public bool $isPublic = false;
};

Props od rodiča: #[Prop]

Hodnoty odovzdané z rodičovskej šablóny sa dajú deklarovať výslovne. Verejné rozhranie komponentu je tak čitateľné na prvý pohľad a oddeľuje „toto prichádza zvonku“ od „toto je interný stav“.

resources/views/components/⚡alert.blade.php
<?php

use Livewire\Component;
use Livewire\Attributes\Prop;

new class extends Component {
    #[Prop]
    public string $type = 'info';

    #[Prop]
    public bool $dismissible = false;
};

?>

<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
    {{ $slot }}

    @if ($dismissible)
        <button wire:click="$dispatch('dismiss')">×</button>
    @endif
</div>
Blade
<livewire:alert type="warning" dismissible class="mt-4">
    The invoice is overdue.
</livewire:alert>

mount() beží stále ako prvý

PHP
use App\Models\Order;

new class extends Component {
    public Order $order;
    public string $mode;

    public function mount(Order $order, string $mode = 'compact'): void
    {
        $this->order = $order;
        $this->mode  = $mode;
    }
};

#[Locked] je rovnako dôležitý ako predtým

PHP
use Livewire\Attributes\Locked;

new class extends Component {
    #[Locked]
    public int $invoiceId;   // klient nemôže podstrčiť iné id

    public string $note = '';
};
Štvrtá verzia nemení nič na modeli hrozieb: každá verejná vlastnosť je zapisovateľná klientom, kým ju nezamknete, a každá verejná metóda je dosiahnuteľný endpoint. Pozri kapitolu 25.

6. wire:model vo štvrtej verzii

Táto zmena vás podrazí s najväčšou pravdepodobnosťou. Dva aspekty wire:model sa vo v4 správajú inak a oba zlyhávajú ticho, nie hlučne.

Zmena 1: modifikátory teraz riadia synchronizáciu na klientovi

Vo v3 .blur a .change určovali len to, kedy odíde sieťová požiadavka. Vo v4 určujú, kedy sa hodnota vôbec synchronizuje — aj na klientovi. Pre staré správanie pridajte .live.

Blade
{{-- Livewire 3 --}}
<input wire:model.blur="title">

{{-- Ekvivalent rovnakého správania vo v4 --}}
<input wire:model.live.blur="title">

Zmena 2: udalosti už nebublajú od potomkov

wire:model na obale už nezachytáva udalosti bublajúce z vnorených polí. Ak ste sa na to spoliehali, pridajte .deep.

Blade
{{-- Livewire 3: obal zachytil udalosť poľa --}}
<div wire:model="value">
    <input type="text">
</div>

{{-- Livewire 4: zapneme výslovne --}}
<div wire:model.deep="value">
    <input type="text">
</div>

Zvyšok bez zmeny

Blade
{{-- Predvolene odložené --}}
<input type="text" wire:model="name">

{{-- Požiadavka pri každej zmene --}}
<input type="text" wire:model.live="search">

{{-- Živé vyhľadávanie s oneskorením --}}
<input type="text" wire:model.live.debounce.400ms="search">

{{-- Vnorené dáta --}}
<input wire:model="form.address.city">
<input wire:model="post.title">
Väzba na vlastnosť modelu (post.title) stále vyžaduje zodpovedajúce validačné pravidlo. Je to ochrana pred hromadným priradením a do v4 prešla nezmenená.

7. Akcie, async a renderless

Akcie sa deklarujú presne ako predtým — verejné metódy volané zo značkovania.

PHP
new class extends Component {
    public function save()
    {
        $this->validate();
        // …
    }
};
Blade
<button wire:click="save">Save</button>

<form wire:submit="save">…</form>

<button wire:click="delete({{ $post->id }})"
        wire:confirm="Delete this post? This cannot be undone.">Delete</button>

Akcie bez prekreslenia

Keď akcia nemení nič, čo používateľ vidí — zvýšenie počítadla zobrazení, zápis riadku auditu —, vynechanie prekreslenia ušetrí celý prechod šablónou aj porovnanie DOM.

PHP
use Livewire\Attributes\Renderless;

new class extends Component {
    #[Renderless]
    public function incrementViewCount(): void
    {
        $this->post->increment('views');
    }
};
Blade
{{-- Alebo zo strany šablóny --}}
<button type="button" wire:click.renderless="incrementViewCount">Track</button>

Imperatívnym ekvivalentom vnútri metódy je stále $this->skipRender().

Asynchrónne akcie

#[Async] (alebo modifikátor .async) vykoná akciu paralelne, mimo bežného frontu požiadaviek. Ideálne pre „vystrelil a zabudol“: analytika, logovanie, zahrievanie cache.

PHP
use Livewire\Attributes\Async;

new class extends Component {
    #[Async]
    public function logInteraction(string $element): void
    {
        Analytics::record($element, auth()->id());
    }
};
Blade
<button wire:click.async="logInteraction('cta-hero')">Get started</button>
Nikdy nepoužívajte async akciu, ktorá mení stav zobrazený v UI. Keďže obchádza front požiadaviek, jej výsledok môže doraziť mimo poradia voči ostatným aktualizáciám a dostanete stav, ktorý si protirečí s obrazovkou. Async je pre vedľajšie efekty, ktoré rozhranie nečíta späť.

Magické akcie

Blade
<button wire:click="$refresh">Refresh</button>
<button wire:click="$set('tab', 'settings')">Settings</button>
<button wire:click="$toggle('showFilters')">Filters</button>
<button wire:click="$dispatch('open-modal', { name: 'create' })">New</button>
<button wire:click="$parent.closeModal()">Close</button>
Bezpečnosť sa nezmenila. Každý parameter autorizujte na serveri a pomocné metódy označte ako protected alebo private, aby sa nedali zavolať z klienta.

8. Životný cyklus a hooky

Životný cyklus je oproti tretej verzii nezmenený. Znalosť poradia stále odstráni väčšinu mätúcich chýb.

Prvé vykreslenie
1. Component instance created
2. boot()
3. mount($params)
4. booted()
5. render()
Následná aktualizácia
 1. POST /livewire-{hash}/update arrives with the state snapshot
 2. Snapshot checksum verified
 3. Component instance created
 4. boot()
 5. State restored from the snapshot
 6. hydrate() / hydrateFoo()
 7. booted()
 8. updating($prop, $value) / updatingFoo($value)
 9. Properties receive new values
10. updated($prop, $value) / updatedFoo($value)
11. Queued actions run
12. rendering() → render() → rendered($view, $html)
13. dehydrate() — state packed back into the snapshot
14. Response: markup + effects
PHP
new class extends Component {
    public float $price = 0;

    public function boot(): void {}
    public function booted(): void {}
    public function hydrate(): void {}
    public function dehydrate(): void {}

    public function updating(string $property, mixed $value): void {}

    public function updated(string $property, mixed $value): void
    {
        $this->validateOnly($property);
    }

    // Pre konkrétnu vlastnosť
    public function updatedPrice(mixed $value): void
    {
        $this->price = round((float) $value, 2);
    }

    // Vnorený kľúč form.email
    public function updatedFormEmail(mixed $value): void
    {
        $this->form['email'] = strtolower(trim($value));
    }
};
Ostrovy menia rozsah vykresľovania, nie poradie týchto hookov. Aktualizácia ostrova stále prebehne celým serverovým životným cyklom — len vráti fragment namiesto celého komponentu.

9. Validácia a Form objekty

Validácia prešla z v3 bez zmeny, vrátane atribútov a Form objektov.

PHP
use Livewire\Attributes\Validate;

new class extends Component {
    #[Validate('required|string|min:2|max:80')]
    public string $name = '';

    #[Validate('required|email:rfc,dns')]
    public string $email = '';

    #[Validate('accepted', message: 'Please agree to the processing of your data.')]
    public bool $consent = false;

    public function submit(): void
    {
        $data = $this->validate();

        Contact::create($data);

        $this->reset();
    }
};

Podmienené pravidlá

PHP
protected function rules(): array
{
    return [
        'email' => [
            'required',
            'email',
            Rule::unique('users', 'email')->ignore($this->userId),
        ],
        'password' => $this->userId ? 'nullable|min:8|confirmed' : 'required|min:8|confirmed',
    ];
}

Form objekty

app/Livewire/Forms/PostForm.php
<?php

namespace App\Livewire\Forms;

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

class PostForm extends Form
{
    public ?Post $post = null;

    #[Validate('required|string|min:5|max:180')]
    public string $title = '';

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

    public function setPost(Post $post): void
    {
        $this->post  = $post;
        $this->title = $post->title;
        $this->body  = $post->body;
    }

    public function store(): Post
    {
        $this->validate();

        return Post::create($this->except('post'));
    }

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

        $this->post->update($this->except('post'));
    }
}
Jednosúborový komponent, ktorý ho používa
<?php

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

new class extends Component {
    public PostForm $form;

    public function save()
    {
        $this->form->post ? $this->form->update() : $this->form->store();

        $this->redirect(route('posts.index'), navigate: true);
    }
};

?>

<div>
    <form wire:submit="save">
        <input wire:model="form.title">
        @error('form.title') <span>{{ $message }}</span> @enderror

        <textarea wire:model="form.body"></textarea>
        @error('form.body') <span>{{ $message }}</span> @enderror

        <button type="submit">Save</button>
    </form>
</div>

Chyby v JavaScripte

Štvrtá verzia sprístupňuje validačné chyby na klientovi cez magickú vlastnosť $errors.

Blade
<div x-show="$errors.has('email')" x-text="$errors.first('email')"></div>

10. Ostrovy (islands)

Ostrovy sú vlajkovou novinkou Livewire 4 a tou, ktorá mení uvažovanie o veľkosti komponentu. Ostrov je oblasť vnútri komponentu, ktorá sa prekresľuje nezávisle: pri aktualizácii sa prepočíta a zaplátkuje len tento fragment, nie celý komponent.

Blade
@island
    <div>Revenue: {{ $this->revenue }}</div>
@endisland

Prečo na tom záleží

Vo v3 bol štandardným liekom na „dashboard je pomalý“ rozpad na šesť podkomponentov, aby aktualizácia jedného widgetu nespúšťala znova dotazy ostatných piatich. Ostrovy dajú rovnakú izoláciu bez hranice komponentu: jeden komponent, jedna trieda, viacero nezávisle sa aktualizujúcich oblastí.

Dashboard s tromi ostrovmi
<?php

use Livewire\Component;
use Livewire\Attributes\Computed;

new class extends Component {
    #[Computed]
    public function revenue()
    {
        return Order::whereMonth('created_at', now()->month)->sum('total');
    }

    #[Computed]
    public function queue()
    {
        return Job::pending()->count();
    }

    #[Computed]
    public function feed()
    {
        return Activity::latest()->take(20)->get();
    }
};

?>

<div>
    @island(name: 'revenue')
        <div class="card">
            <h3>Revenue this month</h3>
            <p class="stat">{{ number_format($this->revenue, 2) }} €</p>
        </div>
    @endisland

    @island(name: 'queue', poll: '5s')
        <div class="card">
            <h3>Jobs pending</h3>
            <p class="stat">{{ $this->queue }}</p>
        </div>
    @endisland

    @island(name: 'feed', lazy: true)
        @placeholder
            <div class="card skeleton animate-pulse h-64"></div>
        @endplaceholder

        <div class="card">
            @foreach ($this->feed as $activity)
                <div wire:key="activity-{{ $activity->id }}">{{ $activity->summary }}</div>
            @endforeach
        </div>
    @endisland
</div>

Možnosti

MožnosťÚčinok
nameIdentifikuje ostrov, aby naň mohli cieliť akcie a JavaScript. Viacero ostrovov s rovnakým menom sa vždy vykresľuje ako skupina.
lazyVykreslí sa, keď ostrov príde do viditeľnej oblasti (intersection observer).
deferVykreslí sa hneď po načítaní stránky bez ohľadu na viditeľnosť.
alwaysVynúti aktualizáciu ostrova pri každom prekreslení rodiča.
skipÚplne vynechá prvé vykreslenie.

Zacielenie ostrova z akcie

Blade
@island(name: 'revenue')
    Revenue: {{ $this->revenue }}
@endisland

<button wire:click="$refresh" wire:island="revenue">Refresh revenue</button>

Append a prepend — nekonečný zoznam bez inštalatérstva

Blade
@island(name: 'feed')
    @foreach ($this->posts as $post)
        <article wire:key="post-{{ $post->id }}">{{ $post->title }}</article>
    @endforeach
@endisland

<button wire:click="loadMore" wire:island.append="feed">Load more</button>

To isté riadené z Alpine alebo čistého JavaScriptu:

Blade
<button x-on:click="$wire.$island('feed', { mode: 'append' }).loadMore()">
    Load more
</button>

Polling v rámci ostrova

Blade
@island(name: 'queue')
    <div wire:poll.3s>
        Jobs pending: {{ $this->queue }}
    </div>
@endisland

Polling obnovuje len ostrov. Porovnajte to s v3, kde wire:poll na dashboarde spúšťal každých pár sekúnd znova všetky dotazy na stránke.

Ostrov alebo podkomponent. Ostrov vtedy, keď oblasť zdieľa stav rodiča a potrebuje len izolované vykresľovanie. Podkomponent vtedy, keď oblasť potrebuje vlastný stav, vlastný životný cyklus alebo sa používa na viacerých miestach.

11. Sloty a preposielanie atribútov

Livewire komponenty teraz prijímajú obsah slotu tak, ako to Blade komponenty vždy vedeli — s jednou dôležitou zvláštnosťou: obsah slotu sa vyhodnocuje v kontexte rodiča. wire:click napísaný v slote volá metódu rodiča, nie potomka.

Predvolený slot

Rodičovská šablóna
<livewire:modal>
    <h2>Create a post</h2>

    <form wire:submit="save">
        <input wire:model="title">
        <button type="submit">Save</button>
    </form>
</livewire:modal>
resources/views/components/⚡modal.blade.php
<?php

use Livewire\Component;

new class extends Component {
    public bool $isOpen = false;

    public function toggle(): void
    {
        $this->isOpen = ! $this->isOpen;
    }
};

?>

<div wire:show="isOpen" class="modal">
    <button wire:click="toggle" class="modal__close">×</button>

    <div class="modal__body">
        {{ $slot }}
    </div>
</div>

V tomto príklade wire:submit="save" a wire:model="title" patria rodičovskému komponentu, zatiaľ čo wire:click="toggle" patrí modálu. Presne také rozdelenie chcete: modál vlastní otváranie a zatváranie, rodič vlastní formulár.

Pomenované sloty

Rodičovská šablóna
<livewire:modal>
    <wire:slot name="header">
        <h2>Create a post</h2>
    </wire:slot>

    <form wire:submit="save">
        <input wire:model="title">
    </form>

    <wire:slot name="footer">
        <button wire:click="save">Save</button>
        <button wire:click="$parent.close()">Cancel</button>
    </wire:slot>
</livewire:modal>
Vnútri komponentu
<div class="modal">
    @if ($header = $slot('header'))
        <div class="modal__header">{{ $header }}</div>
    @endif

    <div class="modal__body">{{ $slot }}</div>

    @if ($footer = $slot('footer'))
        <div class="modal__footer">{{ $footer }}</div>
    @endif
</div>

Preposielanie atribútov

Rovnako ako Blade komponenty môže Livewire komponent prijímať a zlučovať ľubovoľné HTML atribúty cez $attributes.

resources/views/components/⚡alert.blade.php
<?php

use Livewire\Component;
use Livewire\Attributes\Prop;

new class extends Component {
    #[Prop]
    public string $type = 'info';
};

?>

<div {{ $attributes->merge(['class' => 'alert alert-'.$type]) }}>
    {{ $slot }}
</div>
Blade
<livewire:alert type="danger" class="mt-6" data-testid="overdue-alert">
    This invoice is 14 days overdue.
</livewire:alert>
Pri vykresľovaní celostránkového komponentu môžu byť pomenované sloty určené pre layout umiestnené mimo koreňového elementu komponentu.

12. Vnorené komponenty a wire:key

Vnáranie funguje ako vo v3: každý potomok je nezávislá jednotka s vlastným stavom a vlastným cyklom aktualizácie.

Blade
<div>
    @foreach ($orders as $order)
        <livewire:order-row :order="$order" :key="'order-'.$order->id" />
    @endforeach
</div>

Inteligentné kľúče

Vo štvrtej verzii je smart_wire_keys zapnuté predvolene, takže Livewire odvodí kľúče sám v mnohých situáciách s cyklami, kde predtým bol potrebný výslovný. Ubudne tým opakujúceho sa kódu, no kľúče to nerobí zbytočnými.

Kľúče píšte ďalej tam, kde záleží na identite. Každý zoznam, ktorý sa dá preusporiadať, filtrovať alebo čiastočne mazať, musí niesť výslovný wire:key naviazaný na id záznamu. Inteligentné kľúče sú pohodlie pre jednoduché prípady, nie náhrada za to, aby ste frameworku povedali, čo riadok v skutočnosti je.
Blade
@foreach ($rows as $row)
    <div wire:key="row-{{ $row->id }}">…</div>
@endforeach

Reaktívne props

PHP
use Livewire\Attributes\Reactive;

new class extends Component {
    #[Reactive]
    public int $quantity;
};

Volanie rodiča

Blade
<button wire:click="$parent.refreshList()">Refresh the list</button>

Obojsmerná väzba na komponent

PHP
use Livewire\Attributes\Modelable;

new class extends Component {
    #[Modelable]
    public int $value = 0;
};
Blade
<livewire:rating-input wire:model.live="review.rating" />
S ostrovmi siahnete po podkomponente menej často. Ak bol jediným dôvodom rozdelenia „aby sa to prekresľovalo samostatne“, ostrov je ľahší.

13. Udalosti

API udalostí sa oproti tretej verzii nezmenilo.

PHP
// Odoslanie
$this->dispatch('post-created');
$this->dispatch('post-created', postId: $post->id, title: $post->title);
$this->dispatch('refresh')->to(OrderList::class);
$this->dispatch('recalculate')->self();
PHP
use Livewire\Attributes\On;

new class extends Component {
    #[On('post-created')]
    public function onPostCreated(int $postId, string $title): void
    {
        // …
    }
};
Blade
<button wire:click="$dispatch('open-modal', { name: 'create-order' })">New order</button>

Udalosti do prehliadača

PHP
$this->dispatch('notify', type: 'success', message: 'Order saved');
Blade
<div x-data="{ show: false, message: '' }"
     x-on:notify.window="message = $event.detail.message; show = true; setTimeout(() => show = false, 3000)"
     x-show="show"
     x-transition
     class="toast">
    <span x-text="message"></span>
</div>
Ostrovy často nahrádzajú udalosti. Klasický vzor v3 „komponent A odošle, komponent B počúva a obnoví sa“ sa nezriedka mení na „obe oblasti sú ostrovy jedného komponentu a akcia cieli na druhý ostrov“ — jedna požiadavka namiesto dvoch.

14. Vypočítané vlastnosti

#[Computed] funguje ako vo v3 a mimoriadne dobre sa kombinuje s ostrovmi: ostrov, ktorý číta vypočítanú vlastnosť, ju prepočíta iba vtedy, keď sa aktualizuje práve tento ostrov.

PHP
use Livewire\Attributes\Computed;

new class extends Component {
    public array $items = [];

    #[Computed]
    public function products()
    {
        return Product::whereIn('id', array_keys($this->items))->get();
    }

    #[Computed]
    public function subtotal(): float
    {
        return $this->products->sum(
            fn ($product) => $product->price * $this->items[$product->id]
        );
    }

    #[Computed]
    public function total(): float
    {
        return round($this->subtotal * 1.2, 2);
    }
};
Blade
@island(name: 'totals')
    <p>Subtotal: {{ number_format($this->subtotal, 2) }} €</p>
    <p>Total incl. VAT: {{ number_format($this->total, 2) }} €</p>
@endisland

Cachovanie nad rámec požiadavky

PHP
#[Computed(persist: true, seconds: 300)]
public function statistics(): array
{
    return [
        'orders'  => Order::whereMonth('created_at', now()->month)->count(),
        'revenue' => Order::whereMonth('created_at', now()->month)->sum('total'),
    ];
}

#[Computed(cache: true, key: 'global-stats')]
public function globalStats(): array
{
    return app(StatsService::class)->build();
}

Vyprázdnenie cache

PHP
unset($this->products, $this->subtotal, $this->total);
V šablóne je vypočítaná vlastnosť $this->products, nikdy nie $products.

15. Stav v URL a v relácii

PHP
use Livewire\Attributes\Url;
use Livewire\Attributes\Session;

new class extends Component {
    #[Url]
    public string $search = '';

    #[Url(as: 'cat')]
    public ?int $categoryId = null;

    #[Url(except: '')]
    public string $sort = 'popular';

    #[Url(keep: true)]
    public int $perPage = 24;

    #[Url(history: true)]
    public string $tab = 'all';

    #[Session]
    public bool $sidebarCollapsed = false;

    #[Session(key: 'admin.table.density')]
    public string $density = 'comfortable';
};

Výsledok: /catalog?search=laptop&cat=5&sort=price-asc&tab=sale

Flash správy

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

    Setting::updateOrCreate(['key' => 'theme'], ['value' => $this->theme]);

    session()->flash('status', 'Settings saved');
}
Blade
@if (session('status'))
    <div class="alert alert-success">{{ session('status') }}</div>
@endif
Každá #[Url] vlastnosť volá pri zmene History API. Pri poliach meniacich sa s každým stlačením klávesy ju kombinujte s wire:model.live.debounce.

16. Nahrávanie súborov

Nahrávanie funguje ako vo verzii 3, cez trait WithFileUploads.

resources/views/components/⚡avatar-uploader.blade.php
<?php

use Livewire\Component;
use Livewire\WithFileUploads;
use Livewire\Attributes\Validate;

new class extends Component {
    use WithFileUploads;

    #[Validate('required|image|mimes:jpg,jpeg,png,webp|max:4096')]
    public $avatar;

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

        $path = $this->avatar->store('avatars', 'public');

        auth()->user()->update(['avatar_path' => $path]);

        $this->reset('avatar');

        $this->dispatch('notify', message: 'Avatar updated');
    }
};

?>

<div>
    <form wire:submit="save">
        <input type="file" wire:model="avatar" accept="image/*">

        <div wire:loading wire:target="avatar">Uploading…</div>

        @if ($avatar)
            <img src="{{ $avatar->temporaryUrl() }}" alt="Preview" class="preview">
        @endif

        @error('avatar') <p class="error">{{ $message }}</p> @enderror

        <button type="submit" wire:loading.attr="disabled">Save</button>
    </form>
</div>

Presný indikátor priebehu

Blade
<div x-data="{ progress: 0, uploading: false }"
     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="avatar">

    <div x-show="uploading" class="progress">
        <div class="progress__bar" :style="`width: ${progress}%`"></div>
    </div>
</div>
config/livewire.php
'temporary_file_upload' => [
    'disk'            => 's3',
    'rules'           => ['file', 'max:12288'],
    'directory'       => 'livewire-tmp',
    'middleware'      => 'throttle:60,1',
    'preview_mimes'   => ['png', 'jpeg', 'jpg', 'webp', 'gif', 'mp4', 'pdf'],
    'max_upload_time' => 5,
],
upload_max_filesize, post_max_size v PHP a client_max_body_size v nginxe musia prevyšovať vaše pravidlo max:, inak nahrávanie zlyhá bez zrozumiteľnej chyby.

17. Stránkovanie

PHP
use Livewire\WithPagination;
use Livewire\Attributes\Url;

new class extends Component {
    use WithPagination;

    #[Url]
    public string $search = '';

    public string $sortField = 'created_at';
    public string $sortDirection = 'desc';

    public function updatedSearch(): void
    {
        $this->resetPage();
    }

    public function sortBy(string $field): void
    {
        if ($this->sortField === $field) {
            $this->sortDirection = $this->sortDirection === 'asc' ? 'desc' : 'asc';
        } else {
            $this->sortField = $field;
            $this->sortDirection = 'asc';
        }

        $this->resetPage();
    }

    public function with(): array
    {
        return [
            'orders' => Order::query()
                ->with('customer')
                ->when($this->search, fn ($q) => $q->where('number', 'like', "%{$this->search}%"))
                ->orderBy($this->sortField, $this->sortDirection)
                ->paginate(25),
        ];
    }
};

Ostrovy menia stránkovanie na nekonečný zoznam

Blade
<div>
    <input type="search" wire:model.live.debounce.400ms="search">

    @island(name: 'rows')
        @foreach ($orders as $order)
            <div wire:key="order-{{ $order->id }}">{{ $order->number }}</div>
        @endforeach
    @endisland

    <button wire:click="nextPage" wire:island.append="rows">Load more</button>
</div>
Na veľkých tabuľkách stojí paginate() dotaz COUNT(*) navyše. Ak nezobrazujete celkový počet strán — a pri postupnom dočítavaní ho zvyčajne nezobrazujete —, simplePaginate() je citeľne lacnejší.

18. Stavy načítavania

Rodina wire:loading sa nezmenila a v4 pridáva na štýlovanie atribúty data-loading.

Blade
<div wire:loading>Loading…</div>
<div wire:loading.remove>Content</div>

<button wire:click="save">Save</button>
<span wire:loading wire:target="save">Saving…</span>

<span wire:loading wire:target="save,delete,publish">Working…</span>
<div wire:loading wire:target.except="search">Updating…</div>

<button wire:click="save" wire:loading.attr="disabled">Save</button>
<button wire:click="save" wire:loading.class="opacity-50 cursor-wait">Save</button>

{{-- Indikátor sa zobrazí, iba ak požiadavka trvá dlhšie ako prah --}}
<div wire:loading.delay>Loading…</div>
<div wire:loading.delay.long>Loading…</div>

Štýlovanie z CSS

CSS
[data-loading] .btn {
    opacity: 0.5;
    pointer-events: none;
}

Neuložené zmeny a pripojenie

Blade
<input wire:model="title">

<span wire:dirty wire:target="title">You have unsaved changes</span>

<div wire:offline class="banner banner--warn">
    No connection to the server. Changes are not being saved.
</div>

19. Optimistické UI na klientovi

Celá trieda interakcií server nikdy nepotrebovala: otvoriť panel, ukázať počítadlo znakov, zafarbiť pole načerveno, keď je text príliš dlhý. Štvrtá verzia im dáva plnohodnotné direktívy, ktoré menia DOM okamžite, úplne bez požiadavky.

wire:show

Blade
{{-- Prepína viditeľnosť cez CSS, okamžite, bez round tripu --}}
<div wire:show="showModal" class="modal">…</div>

<button wire:click="$toggle('showModal')">Open</button>

wire:text

Blade
{{-- Text nasleduje vlastnosť na klientovi --}}
<span wire:text="title"></span>

<input wire:model="title">

wire:bind

Blade
<textarea wire:model="message" maxlength="280"></textarea>

<span wire:text="message.length"></span> / 280

<span wire:bind:class="message.length > 240 && 'text-red-500'">
    Getting long
</span>

Akcie iba na klientovi cez $js

Blade
<?php

new class extends Component {
    public function save() { /* … */ }
};

?>

<div>
    <button wire:click="save">Save</button>

    {{-- Beží výlučne na klientovi --}}
    <button x-on:click="$wire.$js.showToast = true">Show toast</button>
</div>
Optimistické neznamená smerodajné. Tieto direktívy menia to, čo používateľ vidí, skôr než server súhlasil. Všetko, čo ovplyvňuje dáta, oprávnenia alebo peniaze, sa aj tak musí validovať a aplikovať na serveri — stav na klientovi je náhľad, nie zdroj pravdy.
Dobré pravidlo: wire:show / wire:text pre spätnú väzbu, ktorú má používateľ pocítiť okamžite; bežnú akciu pre všetko, čo sa musí uložiť.

20. Drag and drop

Zmena poradia kedysi znamenala pridať SortableJS, napojiť jeho callbacky na akciu Livewire a udržiavať oba modely v synchronizácii. Vo verzii 4 je to direktíva.

Blade
<ul wire:sort="reorder">
    @foreach ($tasks as $task)
        <li wire:sort:item="{{ $task->id }}" wire:key="task-{{ $task->id }}">
            {{ $task->title }}
        </li>
    @endforeach
</ul>
PHP
new class extends Component {
    public function reorder(array $order): void
    {
        foreach ($order as $position => $id) {
            Task::where('id', $id)->update(['position' => $position]);
        }
    }
};

Úchyty na ťahanie

Blade
<ul wire:sort="reorder">
    @foreach ($tasks as $task)
        <li wire:sort:item="{{ $task->id }}" wire:key="task-{{ $task->id }}">
            <span wire:sort:handle class="cursor-grab">⠿</span>

            <span>{{ $task->title }}</span>

            {{-- Interaktívne prvky by nemali spúšťať ťahanie --}}
            <button wire:sort:ignore wire:click="delete({{ $task->id }})">Delete</button>
        </li>
    @endforeach
</ul>

Ťahanie medzi zoznamami

Blade
<div class="board">
    @foreach ($columns as $column)
        <ul wire:sort="moveCard" wire:sort:group="board" wire:key="column-{{ $column->id }}">
            @foreach ($column->cards as $card)
                <li wire:sort:item="{{ $card->id }}" wire:key="card-{{ $card->id }}">
                    {{ $card->title }}
                </li>
            @endforeach
        </ul>
    @endforeach
</div>
Poradie treba uložiť. Direktíva preusporiada DOM optimisticky a odovzdá vám novú postupnosť — zapísať ju do databázy je na vás. Ak handler vyhodí výnimku, UI a dáta sa rozchádzajú až do ďalšieho úplného vykreslenia.

21. Scoped CSS a skripty

Keďže komponent je teraz jeden súbor, patria doň aj jeho štýly a skripty. Livewire obmedzí CSS na komponent, takže nemôže presiaknuť do zvyšku stránky.

resources/views/components/⚡pricing-card.blade.php
<?php

use Livewire\Component;
use Livewire\Attributes\Prop;

new class extends Component {
    #[Prop]
    public string $plan = 'starter';
};

?>

<div class="card">
    <h3 class="title">{{ ucfirst($plan) }}</h3>
    <p class="price">{{ $this->price }} € / month</p>
</div>

<style>
    /* Scoped to this component — no global .title collision */
    .card  { border: 1px solid #e4e2da; border-radius: 14px; padding: 24px; }
    .title { font-size: 20px; font-weight: 700; }
    .price { color: #2d6a4f; }
</style>

Zámerne globálne štýly

Blade
<style global>
    :root { --brand: #f53004; }
</style>

Skripty komponentu

Blade
@script
<script>
    const chart = new Chart(document.getElementById('sales'), {
        type: 'line',
        data: @json($chartData),
    });

    $wire.on('data-updated', ({ points }) => {
        chart.data.datasets[0].data = points;
        chart.update();
    });
</script>
@endscript
Blade
{{-- Knižnicu tretej strany načítame raz pre celú stránku --}}
@assets
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
@endassets
Scoped CSS je pohodlie pre lokálne štýlovanie komponentu, nie náhrada dizajnového systému. Tokeny, typografiu a základné prvky layoutu držte v globálnom štýle; v komponente nechajte len tých pár pravidiel, ktoré zaujímajú iba jeho.

23. Integrácia s JavaScriptom

Alpine.js sa stále dodáva s Livewire a $wire zostáva mostom z JavaScriptu do stavu komponentu.

Blade
<div x-data="{ open: false }">
    <button x-on:click="open = !open">Details</button>

    <div x-show="open">
        <p x-text="$wire.title"></p>

        <button x-on:click="$wire.title = 'New title'">Rename</button>
        <button x-on:click="$wire.save()">Save</button>
        <button x-on:click="await $wire.calculate(); open = false">Calculate</button>
    </div>
</div>
Blade
{{-- Obojsmerná väzba do Alpine --}}
<div x-data="{ query: $wire.entangle('search') }">
    <input x-model="query">
</div>

wire:ref — pomenovanie prvkov a komponentov

Blade
<livewire:modal wire:ref="modal" />

<button x-on:click="$refs.modal.open()">Open the modal</button>

#[Json] — vrátenie dát priamo do JavaScriptu

PHP
use Livewire\Attributes\Json;

new class extends Component {
    #[Json]
    public function searchSuggestions(string $term): array
    {
        return Product::search($term)->take(5)->pluck('name')->all();
    }
};
Blade
<input x-on:input.debounce.300ms="suggestions = await $wire.searchSuggestions($event.target.value)">

Interceptory

Verzia 4 nahrádza hooky commit a request z v3 metódami interceptMessage() a interceptRequest().

JavaScript
document.addEventListener('livewire:init', () => {

    Livewire.interceptRequest(({ options, fail }) => {
        options.headers['X-Tenant'] = window.tenantId;

        fail(({ status, preventDefault }) => {
            if (status === 419) {
                preventDefault();
                window.location.reload();   // CSRF token vypršal
            }
        });
    });

    Livewire.interceptMessage(({ component, succeed }) => {
        succeed(() => {
            console.debug('component updated', component.name);
        });
    });
});
JavaScript
// Programový prístup
Livewire.dispatch('refresh-orders');
Livewire.find('component-id').call('save');
Livewire.all().forEach((component) => component.$refresh());

Ignorovanie podstromu

Blade
<div wire:ignore>
    <select id="select2-field">…</select>
</div>

<div wire:ignore.self>…</div>

24. Testovanie

Pest je odporúčaný spôsob testovania komponentov Livewire 4. Komponenty založené na šablóne môžu mať test hneď vedľa komponentu namiesto samostatného stromu.

Bash
php artisan make:livewire post.create --test
# resources/views/components/post/create.test.php

Testovanie komponentu založeného na šablóne

Na komponent sa odkazujte menom v bodkovej notácii, nie triedou:

PHP
use Livewire\Livewire;

it('renders', function () {
    Livewire::test('post.create')
        ->assertStatus(200);
});

it('validates required fields', function () {
    Livewire::test('post.create')
        ->set('title', '')
        ->set('body', 'too short')
        ->call('save')
        ->assertHasErrors(['title' => 'required']);
});

it('stores a valid post', function () {
    Livewire::actingAs($user)
        ->test('post.create')
        ->set('title', 'A perfectly reasonable title')
        ->set('body', str_repeat('Body copy that is long enough. ', 3))
        ->call('save')
        ->assertHasNoErrors()
        ->assertDispatched('notify');

    expect(Post::where('title', 'A perfectly reasonable title')->exists())->toBeTrue();
});

Komponenty založené na triede

PHP
use App\Livewire\Counter;

it('increments', function () {
    Livewire::test(Counter::class)
        ->assertSet('count', 0)
        ->call('increment')
        ->assertSet('count', 1);
});

Hlavné asercie

MetódaOveruje
assertSet() / assertNotSet()Hodnoty vlastností
assertSee() / assertDontSee()Vykreslený výstup
assertViewHas()Dáta odovzdané šablóne
assertHasErrors() / assertHasNoErrors()Validáciu
assertDispatched()Udalosti
assertRedirect()Presmerovania
assertUnauthorized() / assertForbidden()Autorizáciu
assertStatus()HTTP status
PHP
// Nahrávanie súborov
use Illuminate\Http\UploadedFile;

Livewire::test('avatar-uploader')
    ->set('avatar', UploadedFile::fake()->image('avatar.jpg', 400, 400))
    ->call('save')
    ->assertHasNoErrors();

// Komponent vnútri stránky
$this->get('/dashboard')
    ->assertSeeLivewire('pages::dashboard');
Testujte prednostne autorizáciu v akciách, validačné pravidlá a prechody stavov. Práve tam sa funkcionalita láme a skrývajú sa bezpečnostné diery — ostrovy ani sloty na tom nič nemenia.

25. Bezpečnosť a výkon

Model hrozieb je zhodný s v3. Každá verejná metóda je otvorený HTTP endpoint, každá verejná vlastnosť je zapisovateľná klientom. Jednosúborové komponenty sa ľahšie prelistujú — a preto sa pri nich ľahšie prehliadne aj chýbajúca kontrola autorizácie.

Kontrolný zoznam bezpečnosti

  • $this->authorize() v každej akcii, ktorá mení dáta.
  • Všetky identifikátory označené #[Locked].
  • Pomocné metódy deklarované ako protected alebo private, aby ich klient nemohol volať.
  • Validačné pravidlá neobsahujú služobné polia (user_id, role, price).
  • Žiadne tokeny, kľúče ani nadbytočné osobné údaje vo verejných vlastnostiach — snapshot ide do prehliadača v čitateľnej podobe.
  • Nahrávanie súborov obmedzené podľa MIME typu a veľkosti.
  • Prihlasovacie a kontaktné formuláre za rate limiterom.
  • {!! !!} iba pre dôveryhodné alebo sanitizované HTML.
  • Optimistické UI sa nikdy nepovažuje za smerodajné.
PHP
public function delete(int $postId): void
{
    $post = Post::findOrFail($postId);

    $this->authorize('delete', $post);

    $post->delete();
}

Výkon

PríznakRiešenie vo v4
Aktualizácia widgetu spustí znova všetky dotazy stránkyZabaliť oblasti do @island
Obrovské HTML stránkyDostať kolekcie modelov z verejných vlastností; načítať ich v with() alebo #[Computed]
Požiadavka pri každom stlačení klávesywire:model.live.debounce.400ms
Záťaž z pollinguPolling vnútri ostrova, pridať .visible
Round trip kvôli prepnutiu paneluwire:show namiesto akcie
Inkrement počítadla prekresľuje stránku#[Renderless]
Dotazy N+1Eager loading cez with(); Model::preventLazyLoading() pri vývoji
Pomalé prvé vykreslenie ťažkého bloku@island(lazy: true) s @placeholder
app/Providers/AppServiceProvider.php
public function boot(): void
{
    Model::preventLazyLoading(! app()->isProduction());
}

26. Časté chyby a ťahák

Komponent sa vôbec nevykreslí

Tag nie je samouzatvorený. Vo v4 <livewire:my-component> nevytvorí nič — a to potichu. Píšte <livewire:my-component />.

V produkcii všetko vracia 404, lokálne funguje

Endpoint Livewire sa presunul z /livewire/ na /livewire-{hash}/. Pravidlo firewallu, výnimka WAF, pravidlo CDN alebo location v nginxe, ktoré sú stále naviazané na starú doslovnú cestu, zablokujú aktualizačné požiadavky.

Pole prestalo synchronizovať po upgrade

wire:model.blur a .change teraz riadia synchronizáciu na klientovi, nielen sieťovú komunikáciu. Pridajte .live: wire:model.live.blur="title".

Obal prestal zachytávať svoje pole

Bublanie udalostí je predvolene vypnuté. Použite wire:model.deep.

Modifikátory wire:transition nič nerobia

.opacity, .scale a .duration.200ms boli odstránené — v4 používa natívne View Transitions API. Animáciu namiesto toho vyjadrite v CSS.

Ostrov sa nikdy neaktualizuje

  • Ostrov nemá name, ale akcia cieli na meno.
  • wire:island="…" ukazuje na meno, ktoré vo vykreslenom výstupe neexistuje.
  • Oblasť závisí od stavu rodiča, ktorý sa reálne nezmenil — pridajte always: true.

Obsah slotu volá nesprávnu metódu

Je to zámer: markup slotu sa vyhodnocuje v kontexte rodiča. Ak chcete volať potomka, použite udalosť alebo wire:ref.

Komponenty Volt prestali fungovať

Volt sa stal súčasťou jadra. Nahraďte Livewire\Volt\Component za Livewire\Component, Volt::route() za Route::livewire(), Volt::test() za Livewire::test() a odstráňte service provider a balík Volt.

Ťahák direktív

DirektívaÚčelNové vo v4
wire:modelVäzba poľa na vlastnosťzmenená sémantika
wire:model.deepZachytiť udalosti z potomkováno
wire:click / wire:submitZavolať akciu—
wire:click.asyncVykonať akciu paralelneáno
wire:click.renderlessPreskočiť prekreslenieáno
wire:islandZacieliť ostrov z akcieáno
wire:island.appendPridať do ostrova namiesto nahradeniaáno
wire:showPrepnúť viditeľnosť na klientoviáno
wire:textNaviazať text na klientoviáno
wire:bindReaktívne naviazať atribútáno
wire:sortZmena poradia cez drag and dropáno
wire:intersectAkcia pri vstupe prvku do viewportuáno
wire:refPomenovať prvok alebo komponent pre JSáno
wire:navigateNavigácia v štýle SPA—
wire:navigate:scrollZachovať scroll kontajnerapremenované
wire:loading / wire:dirty / wire:offlineStav požiadavky—
wire:pollPeriodická aktualizáciav rámci ostrova
wire:keyIdentita prvku v cyklesmart keys predvolene zapnuté
wire:ignoreVylúčiť podstrom z morphingu—

Blade direktívy

DirektívaÚčel
@island … @endislandNezávisle vykresľovaná oblasť
@placeholder … @endplaceholderZástupný obsah pre lenivý ostrov
<wire:slot name="…">Obsah pomenovaného slotu
@script … @endscriptJavaScript v rámci komponentu
@assets … @endassetsAssety stránky načítané raz
@persist … @endpersistZachovať prvok naprieč navigáciami
<style> / <style global>Scoped / globálne CSS komponentu

PHP atribúty

AtribútÚčel
#[Validate]Validačné pravidlo
#[Locked]Zablokovať zápis z frontendu
#[Computed]Cachovaná odvodená hodnota
#[Url] / #[Session]Uchovanie stavu
#[On]Poslucháč udalosti
#[Prop]Deklarovať prop odovzdaný rodičom
#[Reactive] / #[Modelable]Väzba rodič – potomok
#[Async]Vykonať akciu paralelne
#[Renderless]Preskočiť prekreslenie
#[Json]Vrátiť dáta priamo do JavaScriptu
#[Lazy] / #[Layout] / #[Title]Načítavanie a rámec stránky

Príkazy Artisan

Bash
php artisan make:livewire post.create              # jednosúborový
php artisan make:livewire post.create --mfc        # viacsúborový
php artisan make:livewire post.create --test       # s testom
php artisan make:livewire pages::dashboard         # s namespace
php artisan livewire:publish --config
php artisan optimize:clear

Oficiálne zdroje

Livewire 4 sa aktívne vyvíja. Ak sa táto dokumentácia a oficiálna dokumentácia rozchádzajú, platí oficiálna dokumentácia — overte si v nej detail skôr, než sa naň spoľahnete v produkcii.
Upravené podľa oficiálnej dokumentácie

Ak sa táto dokumentácia a oficiálny zdroj líšia, pravdu má oficiálny zdroj. Našli ste chybu? Dajte nám vedieť.