Живые пропсы (live props) в Inertia, добавленные в v3.11.0, поддерживают актуальность страницы при изменении данных на сервере. Пометьте пропс как живой, отправьте событие, и каждая страница, отображающая этот пропс, перезагрузит его.

Давайте покажем, как работают живые пропсы, реализовав страницу статуса заказа с помощью Laravel Reverb, чтобы каждый, кто просматривает заказ, видел новый статус при его отправке. Вам понадобятся inertia-laravel 3.7 и Inertia.js 3.11 или более поздние версии:

composer require inertiajs/inertia-laravel:^3.7
npm install @inertiajs/vue3@^3.11

Для React или Svelte установите вместо этого  @inertiajs/react  или  @inertiajs/svelte .

#Установка Reverb и Echo

Запустите установщик бродкастинга с опцией  --reverb :

php artisan install:broadcasting --reverb

Это установит Reverb, добавит ключи  REVERB_*  и  VITE_REVERB_*  в  .env  и создаст  routes/channels.php . Для приложений на Vue и React он также установит соответствующий пакет Echo ( @laravel/echo-vue  или  @laravel/echo-react ) и добавит вызов  configureEcho()  в  resources/js/app.ts  или  app.tsx :

import { configureEcho } from '@laravel/echo-vue'

configureEcho({
  broadcaster: 'reverb',
})

Установщик определяет только Vue и React, поэтому в приложении на Svelte вам нужно будет установить  @laravel/echo-svelte  и самостоятельно добавить тот же вызов  configureEcho() .

#Создание события бродкастинга

Затем создайте событие, представляющее это изменение:

php artisan make:event OrderUpdated

Реализуйте для него  ShouldBroadcast  и верните канал, в который оно должно транслироваться:

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderUpdated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public Order $order) {}

    public function broadcastOn(): PrivateChannel
    {
        return new PrivateChannel("orders.{$this->order->id}");
    }
}

Приватным каналам требуется правило авторизации в  routes/channels.php . Это позволяет прослушивать канал только владельцу заказа:

use App\Models\Order;
use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('orders.{order}', function ($user, Order $order) {
    return $user->id === $order->user_id;
});

#Пометка пропса как живого

В контроллере оберните пропс в  Inertia::live()  и передайте ему экземпляр события:

use App\Events\OrderUpdated;
use App\Models\Order;
use Inertia\Inertia;

public function show(Order $order)
{
    return Inertia::render('Orders/Show', [
        'order' => Inertia::live(fn () => $order->fresh(), on: new OrderUpdated($order)),
    ]);
}

Создание события здесь не запускает его трансляцию. Inertia вызывает его метод  broadcastOn()  для поиска канала, а затем отправляет канал и имя события на страницу.

Передайте значение в виде замыкания (closure), так как Inertia выполняет его при первом рендеринге и каждый раз при перезагрузке пропса.

#Подключение клиента

Во фронтенде передайте транспорт  echo()  в  createInertiaApp()  в  resources/js/app.ts , сразу после вызова  configureEcho() , добавленного установщиком:

import { createInertiaApp } from '@inertiajs/vue3'
import { echo } from '@inertiajs/vue3/echo'
import { configureEcho } from '@laravel/echo-vue'

configureEcho({
  broadcaster: 'reverb',
})

createInertiaApp({
  // your existing options...
  live: echo(),
})

Вам не нужно менять компонент страницы. Он читает пропс  order  в обычном режиме, а Inertia подписывается на канал при загрузке страницы.

#Трансляция события

Диспатчте (вызывайте) событие везде, где изменяется заказ:

$order->update(['status' => 'shipped']);

OrderUpdated::dispatch($order);

Каждая открытая страница, отображающая этот заказ, затем выполняет частичную перезагрузку (partial reload) для пропса  order . У пользователя, который внес изменения, новые данные обычно уже есть из собственного ответа, поэтому вы можете пропустить его вкладку с помощью  toOthers() :

broadcast(new OrderUpdated($order))->toOthers();

Метод  toOthers()  опирается на ID сокета, который Inertia отправляет в заголовке  X-Socket-Id  с каждым запросом с тем же origin (same-origin).

#Запуск Reverb и воркера очередей

Запустите сервер Reverb:

php artisan reverb:start

События, реализующие  ShouldBroadcast , добавляются в очередь, поэтому вам также потребуется запущенный воркер очередей (queue worker). Скрипт  composer run dev  в новых приложениях Laravel запускает его за вас. Если вы его не используете, запустите воркер самостоятельно:

php artisan queue:work

Чтобы пропустить очередь и выполнить трансляцию во время запроса, реализуйте вместо этого  ShouldBroadcastNow .

#Отображение состояния загрузки

Используйте хук  useProp() , чтобы показать, когда Inertia перезагружает пропс:

<script setup>
import { useProp } from '@inertiajs/vue3'

defineProps(['order'])

const { loading } = useProp('order')
</script>

<template>
  <p>Status: {{ order.status }}</p>
  <span v-if="loading">Updating...</span>
</template>

#Передача значения в событии

Каждое событие отправляет запрос на ваш сервер с каждой страницы, прослушивающей его. При большом количестве зрителей вы можете поместить новое значение в полезную нагрузку (payload) события и пропустить эти запросы:

use App\Http\Resources\OrderResource;
use Inertia\Inertia;

public function broadcastWith(): array
{
    return [
        ...Inertia::broadcastProps([
            'order' => OrderResource::make($this->order),
        ]),
    ];
}

Inertia записывает только те пропсы, которые прослушивают это событие, поэтому payload не может изменить пропс, для которого событие не объявлено. Поскольку каждый пользователь на канале получает один и тот же payload, не используйте его для значений, зависящих от того, кто просматривает страницу.

#Троттлинг частых обновлений

По умолчанию Inertia перезагружает каждый живой пропс не чаще одного раза в секунду. Для пропсов, которые часто меняются, установите больший интервал троттлинга в миллисекундах:

'activity' => Inertia::live(fn () => $order->activity, on: new ActivityLogged($order), throttle: 5000),

Inertia также приостанавливает перезагрузки, пока вкладка браузера скрыта, и выполняет их, когда пользователь возвращается. Значения, отправленные с помощью  broadcastProps() , в любом случае записываются на страницу.

#Дополнительное чтение