Как обновить компонент после завершения задания очереди?

#php #laravel #laravel-livewire

#php #laravel #laravel-livewire

Вопрос:

У меня есть таблица products и job_statuses я использую этот пакет: laravel-job-status

В job_statuses вызываемом пакете есть столбец status , который создал этот столбец finished после завершения задания очереди!

Итак, я создал столбец в products таблице с именем job_status_id (связь с job_statuses) просто для сохранения идентификатора статуса задания в таблице products, чтобы узнать, завершено ли это задание!

Просто я создал компонент, используя Livewire только для обновления одного продукта, когда задание завершено, обновите компонент:

 class ProductIndex extends Component
{
    public $product;


    public function mount($product)
    {
        $this->product = $product;
    }

    public function render()
    {
        return view('livewire.merchant.product.index');
    }
}
  

Внутри product-index компонента:

 @if ($product->job_status->status == 'finished')
  // show real image
 
@else
  // show loader 
@endif
  

Мой блейд:

 @foreach ($products as $product)
  <livewire:merchant.product.product-index :product="$product" :key="$product->id">
@endforeach
  

Как обновить компонент продукта, если статус завершен?

Ответ №1:

Вы можете добавить прослушиватель событий в свой компонент, а затем запустить событие из любого места на странице — даже из JavaScript — для обновления компонента.

Чтобы добавить прослушиватель для обновления самого компонента, просто добавьте следующую строку в свой ProductIndex компонент.

 protected $listeners = ['refreshProducts' => '$refresh'];
  

Теперь Livewire будет прослушивать любые refreshProducts события, которые передаются, и как только они будут отправлены, он обновит этот компонент.

Вы также можете настроить его дополнительно, заменив волшебное $refresh действие методом, которому вы можете передавать параметры. Если вы назовете событие так же, как метод, вам не нужно указывать пару ключ / значение (eventname в качестве ключа, methodname в качестве значения), и одного значения будет достаточно. Вот пример,

 protected $listeners = ['refreshProducts'];

// ...

public function refreshProducts($product_id = null) 
{
    // Refresh if the argument is NULL or is the product ID
    if ($product_id === null || $product_id === $this->product->id) {
        // Do something here that will refresh the event
    }
}
  

Из компонента Livewire вы можете генерировать события с помощью

 $this->emit('refreshProducts');` 

// or if you are passing arguments, as with the second example, 
$this->emit('refreshProducts', $productID);
  

Вы также можете генерировать события из JavaScript, выполнив

 <script>
    Livewire.emit('refreshProducts')
</script>
  

Если вы хотите, чтобы очередь запускала это событие после его завершения, вам нужно реализовать что-то, что либо опрашивает сервер с вопросом «завершено ли задание«, а затем запускает событие, либо вы можете использовать Laravel Echo в качестве websocket. Это позволит вам запускать и прослушивать события извне экосистемы Livewire.

Опрос

При опросе вам не нужно выдавать событие для каждого обновления, так как компонент будет обновляться непрерывно .

Опрос — это самый простой способ непрерывного обновления компонента Livewire, он не требует интеграции с websockets, такой как Laravel Echo. Это означает, что каждые X секунд (по умолчанию 2 секунды) ваш компонент будет отправлять AJAX-запрос на ваш сервер, чтобы получить его новейшие данные и повторно отобразить себя с новыми данными.

Это легко достигается путем обертывания компонента wire:poll атрибутом — вот пример использования 5 секунд.

 <div wire:poll.5s>
    <!-- The rest of your view here -->
</div>
  

Однако это означает, что все экземпляры этого компонента будут повторно отображать себя и отправлять собственный AJAX-запрос на сервер для получения новейших данных. Возможно, вам захочется создать «родительский» компонент для всех ваших элементов, тем самым повторно визуализируя только 1 отдельный компонент.

Трансляция и веб-сокеты

Я предполагаю, что вы уже установили Laravel Echo. Теперь — для достижения этой функциональности трансляции сначала необходимо создать событие. Запустите команду

 php artisan make:event ProductStatusUpdated
  

Это создаст событие в вашей appEvents папке. Настройте его так, как вам нужно. После выполнения команды это будет выглядеть примерно так,

 class ProductStatusUpdated
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return IlluminateBroadcastingChannel|array
     */
    public function broadcastOn()
    {
        return new PrivateChannel('channel-name');
    }
}
  

Мы можем изменить канал с PrivateChannel('channel-name') на Channel('products') , это позволяет нам прослушивать его в Livewire в канале products (вы можете назвать канал как угодно, и вы также можете прослушивать частные события — для этого есть документация в документации Livewire, ссылка на которую приведена в нижней части этого ответа).

Это означает broadcastOn , что будет выглядеть примерно так

 public function broadcastOn()
{
    return new Channel('products');
}
  

Затем, после того, как задание завершит свою работу и все статусы будут установлены, запустите это событие из Laravel, используя

 event(new AppEventsProductStatusUpdated);
  

Теперь нам нужно обновить наш прослушиватель в компоненте Livewire, чтобы мы могли фактически прослушивать трансляцию по этому каналу через Laravel Echo (а не события Livewire, которые мы делали раньше).

 protected $listeners = ['echo:products,ProductStatusUpdated' => 'refreshProducts'];
  

И мы закончили! Теперь вы используете Laravel Echo для трансляции события, которое Livewire перехватывает, а затем запускает. Прослушиватель теперь представляет собой пару ключ / значение, где значением по-прежнему является имя метода в компоненте (вы все равно можете использовать вместо этого волшебное действие $refresh , если хотите), а ключ имеет channel,event префикс echo: .

Ресурсы:

Комментарии:

1. Действительно, спасибо! Нужно ли мне устанавливать Websockets? или Laravel Echo ?

2. Если вы хотите использовать websockets, то они прекрасно интегрируются с Livewire. В качестве альтернативы вам нужно использовать опрос (который заставляет Livewire повторно отображать компонент каждые X секунд), я могу обновить ответ, включив в него и пример этого.

3. Нет, я не хочу использовать websockets, я имею в виду. мой вопрос в том, нужно ли мне устанавливать websockets, тогда я буду следовать первому способу, а если нет, я буду использовать второй способ, который вы упомянули!

4. У обоих подходов есть свои плюсы и минусы — опрос может быть намного проще интегрировать, но это означает, что на ваш сервер поступает больше запросов. Это не обязательно должно иметь большое значение, но вы должны знать об этом (вы можете просмотреть вкладку сети в своем браузере, чтобы увидеть, как они запускаются).

5. Laravel Echo — это веб-сокет, pusher — отдельный пакет, но его довольно удобно использовать в сочетании с Echo. Следуйте инструкциям laravel.com/docs/8.x/broadcasting#installing-laravel-echo