Обновление⚓︎
Livewire v4 вносит ряд улучшений и оптимизаций, сохраняя при этом обратную совместимость везде, где это возможно. Это руководство поможет вам обновиться с Livewire v3 до v4.
Плавное обновление
Большинство приложений могут перейти на v4 с минимальными изменениями. Критические изменения в основном касаются обновлений конфигурации и изменений в сигнатурах методов, которые затрагивают только продвинутые сценарии использования.
Хотите сэкономить время? Вы можете использовать Laravel Shift для автоматизации обновления вашего приложения.
Установка⚓︎
Обновите ваш файл composer.json, указав версию Livewire v4:
После обновления очистите кэш вашего приложения:
Посмотреть все изменения на GitHub
Для полного обзора всех изменений в коде между v3 и v4 вы можете просмотреть полный дифф на GitHub: Сравнить 3.x с main →
Обновление до v4.1 с v4.0⚓︎
Изменение поведения модификаторов wire:model⚓︎
Модификаторы, такие как .blur и .change, теперь контролируют момент синхронизации состояния на клиенте, а не только время отправки сетевых запросов. Если вы используете эти модификаторы и хотите сохранить предыдущее поведение, добавьте .live перед ними (например, wire:model.live.blur).
Следующие изменения применимы при обновлении с v3 до v4.
Важные изменения⚓︎
Эти изменения с наибольшей вероятностью затронут ваше приложение, поэтому их следует внимательно изучить.
Обновления файла конфигурации⚓︎
Некоторые ключи конфигурации были переименованы, реорганизованы или получили новые значения по умолчанию. Обновите ваш файл config/livewire.php:
Посмотреть полный файл конфигурации
Для справки вы можете просмотреть полный файл конфигурации v4 на GitHub: livewire.php →
Переименованные ключи конфигурации⚓︎
Конфигурация макета:
// До (v3)
'layout' => 'components.layouts.app',
// После (v4)
'component_layout' => 'layouts::app',
Макет теперь по умолчанию использует пространство имён layouts::, указывая на resources/views/layouts/app.blade.php.
Конфигурация заполнителя:
// До (v3)
'lazy_placeholder' => 'livewire.placeholder',
// После (v4)
'component_placeholder' => 'livewire.placeholder',
Изменённые значения по умолчанию⚓︎
Умное поведение wire
Это помогает предотвратить проблемы с wire:key во вложенных компонентах. Примечание: вам по-прежнему нужно добавлять wire:key вручную в циклах — эта настройка не отменяет этого требования.
Новые опции конфигурации⚓︎
Расположение компонентов:
<?php
'component_locations' => [
resource_path('views/components'),
resource_path('views/livewire'),
],
Определяет, где Livewire ищет однофайловые и многофайловые (основанные на представлениях) компоненты.
Пространства имён компонентов:
<?php
'component_namespaces' => [
'layouts' => resource_path('views/layouts'),
'pages' => resource_path('views/pages'),
],
Создает пользовательские пространства имён для организации компонентов на основе представлений (например, <livewire:pages::dashboard />).
Настройки команды make:
<?php
'make_command' => [
'type' => 'sfc', // Варианты: 'sfc', 'mfc', или 'class'
'emoji' => true, // Использовать ли префикс-эмодзи ⚡
],
Настройка формата компонентов по умолчанию и использования эмодзи. Установите type в 'class', чтобы соответствовать поведению v3.
Режим безопасности CSP:
Включите режим Content Security Policy (CSP), чтобы избежать нарушений unsafe-eval. Когда этот режим включен, Livewire использует CSP-сборку Alpine. Примечание: этот режим ограничивает использование сложных JavaScript-выражений в директивах, таких как wire:click="addToCart($event.detail.productId)", или глобальных ссылок, вроде window.location.
Изменения в маршрутизации⚓︎
Для полностраничных компонентов рекомендуемый подход к маршрутизации изменился:
<?php
// До (v3) — всё ещё работает, но не рекомендуется
Route::get('/dashboard', Dashboard::class);
// После (v4) — рекомендуется для всех типов компонентов
Route::livewire('/dashboard', Dashboard::class);
// Для компонентов на основе представлений можно использовать имя компонента
Route::livewire('/dashboard', 'pages::dashboard');
Использование Route::livewire() теперь является предпочтительным методом и необходимо для корректной работы однофайловых и многофайловых компонентов в качестве полностраничных.
wire:model теперь игнорирует события дочерних элементов по умолчанию⚓︎
В v3 wire:model реагировала на события input/change, которые всплывали от дочерних элементов. Это вызывало неожиданное поведение при использовании wire:model на элементах-контейнерах (таких как модальные окна или аккордеоны), содержащих поля ввода — очистка поля ввода внутри могла привести к всплытию события и потенциальному закрытию модального окна.
В v4 wire:model теперь слушает только события, возникающие непосредственно на самом элементе (аналогично поведению модификатора .self).
Если у вас есть код, который полагается на перехват событий от дочерних элементов, добавьте модификатор .deep:
<!-- До (v3) - прослушивание событий дочерних элементов по умолчанию -->
<div wire:model="value">
<input type="text">
</div>
<!-- После (v4) - добавьте .deep, чтобы восстановить старое поведение -->
<div wire:model.deep="value">
<input type="text">
</div>
Большинству приложений не потребуются изменения
Это изменение в первую очередь затрагивает нестандартное использование wire:model на элементах-контейнерах. Стандартные привязки полей форм (input, select, textarea) не затрагиваются.
Используйте wire:navigate:scroll⚓︎
Если в v3 вы использовали wire:scroll для сохранения позиции прокрутки в прокручиваемом контейнере при переходах wire:navigate, в v4 вам нужно использовать wire:navigate:scroll вместо этого:
@persist('sidebar')
<div class="overflow-y-scroll" wire:scroll>
<div class="overflow-y-scroll" wire:navigate:scroll>
<!-- ... -->
</div>
@endpersist
Теги компонентов должны быть закрыты⚓︎
В v3 теги компонентов Livewire могли рендериться даже без правильного закрытия. В v4, с добавлением поддержки слотов, теги компонентов должны быть закрыты должным образом — иначе Livewire интерпретирует последующее содержимое как контент слота, и компонент не будет отрисован:
<!-- До (v3) - незакрытый тег -->
<livewire:component-name>
<!-- После (v4) - самозакрывающийся тег -->
<livewire:component-name />
Подробнее о рендеринге компонентов →
Изменения средней степени влияния⚓︎
Эти изменения могут затронуть определённые части вашего приложения в зависимости от того, какие функции вы используете.
Модификаторы wire:model теперь контролируют момент синхронизации состояния на клиенте⚓︎
В v3 модификаторы, такие как .blur и .change, контролировали только момент отправки сетевых запросов. Значение поля ввода всегда синхронизировалось с состоянием на стороне клиента ($wire.property) мгновенно, по мере ввода пользователем.
В v4 эти модификаторы теперь контролируют и момент синхронизации состояния на клиенте. Это открывает новые возможности для UI, например, поля ввода, которые не обновляются, пока пользователь не закончит ввод и не нажмет Enter или не переключится на другое поле.
Миграция: Если вы используете .blur или .change и хотите восстановить старое поведение, добавьте .live перед модификатором:
<!-- v3 -->
<input wire:model.blur="title">
<!-- эквивалент v4 -->
<input wire:model.live.blur="title">
| Синтаксис v3 | Эквивалент v4 |
|---|---|
wire:model.blur |
wire:model.live.blur |
wire:model.change |
wire:model.live.change |
.lazy обратно совместим
wire:model.lazy продолжает работать так же, как и в v3 — миграция не требуется.
Новое в v4: Теперь вы можете отложить обновление на клиенте без отправки сетевых запросов:
<!-- Обновлять $wire.width только при потере фокуса -->
<input wire:model.blur="width">
<!-- Обновлять при нажатии Enter или потере фокуса -->
<input wire:model.blur.enter="search">
wire:transition теперь использует View Transitions API⚓︎
В v3 wire:transition был обёрткой вокруг директивы x-transition из Alpine, поддерживая модификаторы, такие как .opacity, .scale, .duration.200ms и .origin.top.
В v4 wire:transition вместо этого использует нативный браузерный View Transitions API. Базовое использование по-прежнему работает — элементы будут плавно появляться и исчезать, — но все модификаторы были удалены.
<!-- Это по-прежнему работает в v4 -->
<div wire:transition>...</div>
<!-- Эти модификаторы больше не поддерживаются -->
<div wire:transition.opacity>...</div>
<div wire:transition.scale.origin.top>...</div>
<div wire:transition.duration.500ms>...</div>
Улучшения производительности⚓︎
Livewire v4 включает значительные улучшения производительности системы обработки запросов:
- Неблокирующий поллинг:
wire:pollбольше не блокирует другие запросы и не блокируется ими - Параллельные обновления: запросы
wire:model.liveтеперь выполняются параллельно, что обеспечивает более быстрый ввод и получение результатов
Эти улучшения применяются автоматически — изменения в вашем коде не требуются.
Хуки обновления консолидируют изменения массивов/объектов⚓︎
При замене всего массива или объекта на фронтенде (например, $wire.items = ['new', 'values']), Livewire теперь отправляет одно консолидированное обновление вместо детальных обновлений для каждого индекса.
До: Установка $wire.items = ['a', 'b'] для массива из 4 элементов вызывала хуки updatingItems/updatedItems несколько раз — по одному для каждого изменения индекса плюс удаления __rm__.
После: Та же операция вызывает хуки один раз с полным новым значением массива, что соответствует поведению v2.
Если ваш код полагается на срабатывание хуков отдельных индексов при замене целых массивов, вам может потребоваться корректировка. Изменения отдельных элементов (например, wire:model="items.0") по-прежнему вызывают детальные хуки, как и ожидалось.
Изменения сигнатур методов⚓︎
Если вы расширяете функциональность ядра Livewire или используете эти методы напрямую, обратите внимание на следующие изменения сигнатур:
Стриминг:
Порядок параметров метода stream() изменился:
<?php
// До (v3)
$this->stream(to: '#container', content: 'Привет', replace: true);
// После (v4)
$this->stream(content: 'Привет', replace: true, el: '#container');
Если вы используете именованные параметры (как показано выше), обратите внимание, что to: было переименовано в el:. Если вы используете позиционные параметры, вам нужно обновить код следующим образом:
<?php
// До (v3) - позиционные параметры
$this->stream('#container', 'Hello');
// После (v4) - позиционные/именованные параметры
$this->stream('Hello', el: '#container');
Монтирование компонентов (внутреннее):
Если вы расширяете LivewireManager или вызываете метод mount() напрямую:
<?php
// До (v3)
public function mount($name, $params = [], $key = null)
// После (v4)
public function mount($name, $params = [], $key = null, $slots = [])
Это изменение добавляет поддержку передачи слотов при монтировании компонентов и, как правило, не затрагивает большинство приложений.
Незначительные изменения⚓︎
Эти изменения затрагивают только те приложения, которые используют расширенные функции или кастомизацию.
wire:model теперь поддерживает нотацию с квадратными скобками⚓︎
Выражения wire:model теперь поддерживают нотацию с квадратными скобками для доступа к вложенным свойствам:
Это означает, что квадратные скобки ([ и ]) в значениях wire:model теперь интерпретируются как операторы доступа к свойствам. В v3 они рассматривались как литеральные символы. Если ваши ключи свойств содержат квадратные скобки, переименуйте их, чтобы избежать конфликтов.
Изменения URL-адресов ресурсов и эндпойнтов Livewire⚓︎
Все URL-адреса Livewire теперь включают уникальный хеш, полученный из вашего APP_KEY. Префикс изменился с /livewire/ на /livewire-{hash}/:
# v3 # v4
/livewire/update → /livewire-{hash}/update
/livewire/upload-file → /livewire-{hash}/upload-file
/livewire/livewire.js → /livewire-{hash}/livewire.js
Если ваши правила брандмауэра, конфигурация CDN или мидлвар ссылаются на пути /livewire/, обновите их с учетом нового префикса.
Если вы используете setUpdateRoute, используйте параметр $path, чтобы сохранить эндпойнт с хешем:
<?php
// До (v3)
Livewire::setUpdateRoute(function ($handle) {
return Route::post('/livewire/update', $handle);
});
// После (v4)
Livewire::setUpdateRoute(function ($handle, $path) {
return Route::post($path, $handle);
});
Подробнее о настройке эндпойнтов Livewire →
Устаревшие JavaScript-методы⚓︎
Устарело: метод $wire.$js()⚓︎
Метод $wire.$js() для определения JavaScript-действий объявлен устаревшим:
// Устарело (v3)
$wire.$js('bookmark', () => {
// Переключить закладку...
})
// Новое (v4)
$wire.$js.bookmark = () => {
// Переключить закладку...
}
Новый синтаксис чище и интуитивно понятнее.
Устарело: $js без префикса⚓︎
Использование $js в скриптах без префикса $wire.$js или this.$js объявлено устаревшим:
// Устарело (v3)
$js('bookmark', () => {
// Переключить закладку...
})
// Новое (v4)
$wire.$js.bookmark = () => {
// Переключить закладку...
}
// Или
this.$js.bookmark = () => {
// Переключить закладку...
}
Старый синтаксис по-прежнему работает
И $wire.$js('bookmark', ...), и $js('bookmark', ...) продолжат работать в v4 для обеспечения обратной совместимости, но вам следует перейти на новый синтаксис, когда это будет удобно.
Устарело: хуки commit и request⚓︎
Хуки commit и request были объявлены устаревшими в пользу новой системы перехватчиков, которая обеспечивает более детальный контроль и лучшую производительность.
Старые хуки по-прежнему работают
Устаревшие хуки продолжат работать в v4 для обеспечения обратной совместимости, но вам следует перейти на новую систему, когда это будет удобно.
Миграция с хука commit⚓︎
Старый хук commit:
// СТАРОЕ - Устарело
Livewire.hook('commit', ({ component, commit, respond, succeed, fail }) => {
respond(() => {
// Запускается после получения ответа, но до его обработки
})
succeed(({ snapshot, effects }) => {
// Запускается после успешного ответа
})
fail(() => {
// Запускается, если запрос завершился ошибкой
})
})
Следует заменить на новый interceptMessage:
// НОВОЕ - Рекомендуется
Livewire.interceptMessage(({ component, message, onFinish, onSuccess, onError, onFailure }) => {
onFinish(() => {
// Эквивалент respond()
})
onSuccess(({ payload }) => {
// Эквивалент succeed()
// Доступ к snapshot через payload.snapshot
// Доступ к effects через payload.effects
})
onError(() => {
// Эквивалент fail() для ошибок сервера
})
onFailure(() => {
// Эквивалент fail() для сетевых ошибок
})
})
Миграция с хука request⚓︎
Старый хук request:
// СТАРОЕ - Устарело
Livewire.hook('request', ({ url, options, payload, respond, succeed, fail }) => {
respond(({ status, response }) => {
// Запускается, когда ответ получен
})
succeed(({ status, json }) => {
// Запускается при успешном ответе
})
fail(({ status, content, preventDefault }) => {
// Запускается при неудачном ответе
})
})
Следует заменить на новый interceptRequest:
// НОВОЕ - Рекомендуется
Livewire.interceptRequest(({ request, onResponse, onSuccess, onError, onFailure }) => {
// Доступ к url через request.uri
// Доступ к options через request.options
// Доступ к payload через request.payload
onResponse(({ response }) => {
// Эквивалент respond()
// Доступ к status через response.status
})
onSuccess(({ response, responseJson }) => {
// Эквивалент succeed()
// Доступ к status через response.status
// Доступ к json через responseJson
})
onError(({ response, responseBody, preventDefault }) => {
// Эквивалент fail() для ошибок сервера
// Доступ к status через response.status
// Доступ к content через responseBody
})
onFailure(({ error }) => {
// Эквивалент fail() для сетевых ошибок
})
})
Ключевые различия⚓︎
- Более детализированная обработка ошибок: Новая система разделяет сетевые сбои (
onFailure) и ошибки сервера (onError) - Улучшенные хуки жизненного цикла: Перехватчики сообщений предоставляют дополнительные хуки, такие как
onSync,onMorphиonRender - Поддержка отмены: И сообщения, и запросы могут быть отменены/прерваны
- Привязка к компоненту: Перехватчики сообщений могут быть привязаны к конкретным компонентам с помощью
$wire.intercept(...)
Полную документацию по новой системе перехватчиков см. в разделе JavaScript-перехватчики.
Обновление Volt⚓︎
Livewire v4 теперь поддерживает однофайловые компоненты, которые используют тот же синтаксис, что и компоненты Volt на основе классов. Это означает, что вы можете перейти с Volt на встроенные однофайловые компоненты Livewire.
Обновление импортов компонентов⚓︎
Замените все вхождения Livewire\Volt\Component на Livewire\Component:
<?php
// До (Volt)
use Livewire\Volt\Component;
new class extends Component { ... }
// После (Livewire v4)
use Livewire\Component;
new class extends Component { ... }
Обновление определений маршрутов⚓︎
Замените Volt::route() на Route::livewire() в ваших файлах маршрутов:
<?php
// До (Volt)
use Livewire\Volt\Volt;
Volt::route('/dashboard', 'dashboard');
// После (Livewire v4)
use Illuminate\Support\Facades\Route;
Route::livewire('/dashboard', 'dashboard');
Обновление тестовых файлов⚓︎
Замените все вхождения Livewire\Volt\Volt на Livewire\Livewire, а также измените Volt::test() на Livewire::test():
<?php
// До (Volt)
use Livewire\Volt\Volt;
Volt::test('counter')
// После (Livewire v4)
use Livewire\Livewire;
Livewire::test('counter')
Удаление провайдера Volt⚓︎
Удалите файл сервис-провайдера Volt:
Затем удалите его из массива провайдеров в файле bootstrap/providers.php:
<?php
// До
return [
App\Providers\AppServiceProvider::class,
App\Providers\VoltServiceProvider::class,
];
// После
return [
App\Providers\AppServiceProvider::class,
];
Удаление пакета Volt⚓︎
Удалите пакет Volt:
Установка Livewire v4⚓︎
После выполнения всех изменений выше установите Livewire v4. Ваши существующие классовые компоненты Volt продолжат работать без каких-либо изменений, поскольку они используют тот же синтаксис, что и однострочные компоненты Livewire.
Новые возможности в v4⚓︎
Livewire v4 привносит несколько мощных новшеств, которыми вы можете начать пользоваться сразу:
Возможности компонентов⚓︎
Однофайловые и многофайловые компоненты
В v4 появились новые форматы компонентов наряду с традиционным классовым подходом. Однофайловые компоненты объединяют PHP и Blade в одном файле, а многофайловые — организуют PHP, Blade, JavaScript и тесты в отдельной директории.
По умолчанию файлы однофайловых компонентов начинаются с эмодзи ⚡, чтобы их легко было отличить от обычных Blade-файлов в редакторе и при поиске. Эту особенность можно отключить в настройке make_command.emoji.
php artisan make:livewire create-post # Однофайловый компонент (по умолчанию)
php artisan make:livewire create-post --mfc # Многофайловый компонент
php artisan livewire:convert create-post # Конвертация между форматами
Подробнее о форматах компонентов →
Слоты и автоматическая передача атрибутов
Компоненты теперь поддерживают слоты и автоматическую передачу всех атрибутов через {{ $attributes }}, что делает композицию компонентов значительно гибче.
Подробнее о вложенных компонентах →
JavaScript в компонентах на основе представления
В компонентах на основе представления теперь можно использовать обычные теги <script> без обёртки @script. Такие скрипты выносятся в отдельные кэшируемые файлы для лучшей производительности и автоматически получают привязку к $wire:
<div>
<!-- Шаблон вашего компонента -->
</div>
<script>
// $wire автоматически привязывается как 'this'
this.count++ // То же самое, что $wire.count++
// $wire всё ещё доступен, если вам так удобнее
$wire.save()
</script>
Подробнее о JavaScript в компонентах →
Островки⚓︎
Островки позволяют создавать изолированные области внутри компонента, которые обновляются независимо друг от друга. Это значительно повышает производительность, при этом не требуя создания отдельных дочерних компонентов.
Улучшения загрузки⚓︎
Отложенная загрузка
Помимо ленивой загрузки (когда компонент загружается при попадании в область видимости), теперь компоненты можно настроить на отложенную загрузку сразу после начальной загрузки страницы:
Пакетная загрузка
Управляйте тем, будут ли несколько ленивых или отложенных компонентов загружаться параллельно или группироваться в один пакет:
Подробнее о ленивой и отложенной загрузке →
Асинхронные действия⚓︎
Запускайте действия параллельно, не блокируя другие запросы, с помощью модификатора .async или атрибута #[Async]:
Подробнее об асинхронных действиях →
Новые директивы и модификаторы⚓︎
wire:sort — сортировка перетаскиванием
Встроенная поддержка сортируемых списков с помощью перетаскивания:
<ul wire:sort="updateOrder">
@foreach ($items as $item)
<li wire:sort:item="{{ $item->id }}" wire:key="{{ $item->id }}">{{ $item->name }}</li>
@endforeach
</ul>
wire:intersect — Пересечение с областью видимости
Запускайте действия, когда элемент входит в область видимости или покидает её. Работает аналогично плагину x-intersect в Alpine.js:
<!-- Обычное использование -->
<div wire:intersect="loadMore">...</div>
<!-- С модификаторами -->
<div wire:intersect.once="trackView">...</div>
<div wire:intersect:leave="pauseVideo">...</div>
<div wire:intersect.half="loadMore">...</div>
<div wire:intersect.full="startAnimation">...</div>
<!-- С параметрами -->
<div wire:intersect.margin.200px="loadMore">...</div>
<div wire:intersect.threshold.50="trackScroll">...</div>
Доступные модификаторы:
.once— срабатывает только один раз.half— ждёт, пока элемент виден хотя бы наполовину.full— ждёт, пока элемент виден полностью.threshold.X— произвольный процент видимости (0–100).margin.Xpxили.margin.X%— отступы зоны пересечения
wire:ref — ссылки на элементы
Простой способ получать ссылки на элементы в шаблоне и взаимодействовать с ними:
<div wire:ref="modal">
<!-- Содержимое модального окна -->
</div>
<button wire:click="$js.scrollToModal">Прокрутить к содержимому</button>
<script>
this.$js.scrollToModal = () => {
this.$refs.modal.scrollIntoView()
}
</script>
Модификатор .renderless
Позволяет пропустить повторный рендеринг компонента прямо из шаблона:
Это альтернатива атрибуту #[Renderless] для действий, которым не нужно обновлять интерфейс.
Модификатор .preserve-scroll
Сохраняет позицию прокрутки во время обновлений, чтобы избежать скачков макета:
Атрибут data-loading
Каждый элемент, который инициирует сетевой запрос, автоматически получает атрибут data-loading. Это позволяет очень просто стилизовать состояния загрузки с помощью Tailwind:
<button wire:click="save" class="data-loading:opacity-50 data-loading:pointer-events-none">
Сохранить изменения
</button>
Подробнее о состояниях загрузки →
Улучшения в JavaScript⚓︎
Магическое свойство $errors
Получайте доступ к bag ошибок компонента прямо из JavaScript:
Магический метод $intercept
Перехватывайте и изменяйте запросы Livewire прямо из JavaScript:
Подробнее о перехватчиках JavaScript →
Запуск островков из JavaScript
Позволяет запускать рендеринг островков прямо из шаблона:
Получение помощи⚓︎
Если во время обновления возникнут проблемы:
- Воспользуйтесь поиском по документации — в ней есть ответы почти на все ваши вопросы
- Загляните в обсуждения на GitHub — там можно получить поддержку от сообщества