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

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

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

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

Просто я создал компонент, используя 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

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


person ali    schedule 03.10.2020    source источник


Ответы (1)


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

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

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

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

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

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 как веб-сокет. Это позволит вам запускать и прослушивать события вне экосистемы Livewire.

Опрос

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

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

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

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

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

Вещание и веб-сокеты

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

php artisan make:event ProductStatusUpdated

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

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 \Illuminate\Broadcasting\Channel|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 \App\Events\ProductStatusUpdated);

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

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

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

Ресурсы:

person Qirel    schedule 03.10.2020
comment
Действительно, спасибо! Мне нужно установить Websockets? или Laravel Echo? - person ali; 03.10.2020
comment
Если вы хотите использовать веб-сокеты, они прекрасно интегрируются с Livewire. В качестве альтернативы вам нужно использовать опрос (который заставляет Livewire повторно отображать компонент каждые X секунд), я могу обновить ответ, включив пример этого тоже. - person Qirel; 03.10.2020
comment
Нет, я не хочу использовать веб-сокеты, я имею в виду. Мой вопрос: если мне нужно установить веб-сокеты, я буду следовать первому способу, а если нет, я буду использовать второй способ, о котором вы упомянули! - person ali; 03.10.2020
comment
У обоих подходов есть свои плюсы и минусы - опрос может быть намного проще интегрировать, но это означает, что на ваш сервер отправляется больше запросов. Не обязательно иметь большое влияние, но это то, о чем вы должны знать (вы можете проверить вкладку сетей в своем браузере, чтобы увидеть, как они увольняются). - person Qirel; 03.10.2020
comment
Но опрос продолжит обновление после завершения очереди! - person ali; 03.10.2020
comment
Да, опрос означает, что страница будет всегда, пока она открыта, обновляться через X секунд (по умолчанию 2, но я показал, например, как вы устанавливаете его на 5 секунд). - person Qirel; 03.10.2020
comment
Последнее! Теперь, если я буду следовать последнему пути (вещание), я должен использовать также веб-сокеты или пушер с ним? Правильно? или просто laravel echo делает эту работу? - person ali; 03.10.2020
comment
Laravel Echo - это веб-сокет, pusher - отдельный пакет, но его очень удобно использовать в сочетании с Echo. Следуйте руководству laravel.com/docs/8.x/broadcasting#installing -ларавелла-эхо - person Qirel; 03.10.2020