Перейти к основному содержимому

Laravel и Livewire

Разработчику

Laravel и Livewire

После первой программы на Laravel у вас классический сайт: форма отправляется, страница полностью перезагружается, сервер отдаёт новый HTML.

Для кнопок «+1 к лайкам», живого поиска по таблице, модальных окон без перезагрузки обычно пишут JavaScript (Vue, React) или берут Livewire.

Livewire — библиотека, где «компонент» — это PHP-класс + Blade-шаблон. При клике или вводе Livewire отправляет лёгкий AJAX-запрос на Laravel, обновляет свойства класса и перерисовывает только нужный фрагмент HTML. Отдельный SPA и сборка webpack для простых задач часто не нужны.

ПодходКогда уместен
Blade + формыПростые CRUD, SEO-страницы, минимум JS
LivewireИнтерактив внутри Laravel одной командой PHP
Sanctum + SPAОтдельный фронт на React/Vue, мобильное приложение
Inertia.jsVue/React, но маршруты остаются в Laravel

Как это работает (без магии)

В layout обязательны @livewireStyles и @livewireScripts — они подключают небольшой JS, который перехватывает действия. CSRF-токен в layout (@csrf или meta) нужен для POST-запросов Livewire.


Установка

composer require livewire/livewire

В resources/views/layouts/app.blade.php перед </body>:

@livewireStyles
@livewireScripts

Первый компонент — счётчик

php artisan make:livewire Counter

Создаются:

  • app/Livewire/Counter.php — логика;
  • resources/views/livewire/counter.blade.php — разметка.

app/Livewire/Counter.php:

<?php

namespace App\Livewire;

use Livewire\Component;

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

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

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

public function render()
{
return view('livewire.counter');
}
}
ЭлементСмысл
public int $countСвойство, видимое шаблону и сериализуемое при запросах Livewire
increment()Публичный метод — можно вызвать из шаблона через wire:click
render()Какой Blade вернуть

Шаблон resources/views/livewire/counter.blade.php:

<div>
<h2>Счётчик: {{ $count }}</h2>
<button type="button" wire:click="increment">+</button>
<button type="button" wire:click="decrement">−</button>
</div>

wire:click="increment" — по клику вызвать метод increment на сервере. Важно type="button", иначе кнопка внутри <form> отправит форму целиком.

Подключение на странице:

@extends('layouts.app')

@section('content')
<h1>Livewire</h1>
<livewire:counter />
@endsection

Маршрут:

Route::view('/livewire-demo', 'counter-page');

php artisan serve/livewire-demo. Страница не перезагружается при +/- .


wire:model — связь поля и свойства

Аналог v-model во Vue: значение input синхронизируется с PHP-свойством.

php artisan make:livewire TaskSearch
<?php

namespace App\Livewire;

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

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

public function render()
{
$tasks = Task::query()
->when($this->query, fn ($q) => $q->where('title', 'like', '%'.$this->query.'%'))
->orderByDesc('id')
->limit(20)
->get();

return view('livewire.task-search', compact('tasks'));
}
}

Шаблон:

<div>
<input type="search"
wire:model.live.debounce.300ms="query"
placeholder="Поиск…" />

<ul class="mt-4">
@forelse ($tasks as $task)
<li>{{ $task->title }}</li>
@empty
<li>Ничего не найдено</li>
@endforelse
</ul>
</div>

Разбор директив

ДирективаСмысл
wire:model="query"Двусторонняя связь с $query
.liveОбновлять при каждом вводе (без ожидания blur)
.debounce.300msЖдать 300 мс паузы в наборе — меньше запросов к серверу

Модель Task: php artisan make:model Task -m, поле title в миграции.


Валидация

Те же правила, что в HTTP-контроллере:

public string $title = '';

public function save(): void
{
$this->validate([
'title' => 'required|string|max:200',
]);

Task::create(['title' => $this->title]);
$this->reset('title');
$this->dispatch('task-saved');
}
<input wire:model="title" />
@error('title') <span class="text-red-600">{{ $message }}</span> @enderror
<button type="button" wire:click="save">Добавить</button>

@error — директива Laravel для сообщений валидации. dispatch('task-saved') — событие для других JS/Livewire-компонентов (опционально).


Livewire и API — разные клиенты

СценарийИнструмент
Сайт в Blade, кнопки и формы на сервереLivewire
Мобильное приложение, отдельный ReactSanctum API

Один проект может совмещать: публичная часть на Livewire, /api для мобильного клиента.


Тестирование Livewire

Livewire::test(Counter::class)
->call('increment')
->assertSet('count', 1);

Без браузера проверяется логика компонента.


Частые ошибки

СимптомПричина
Полная перезагрузка страницыНет @livewireScripts или type="submit" без wire:submit
419Нет CSRF в layout
Свойство не меняетсяСвойство private или опечатка в wire:model
Медленный поискУбрали debounce; нет индекса на title в БД

Что попробовать

  1. Filament — админка на Livewire без ручной вёрстки таблиц.
  2. Trait WithPagination для длинных списков.
  3. Очереди — тяжёлую работу после save() уводить в job.

Связанные материалы


См. также

Другие статьи этого же раздела в боковом меню (как на странице «О разделе»).