队列作业完成后如何刷新组件?

ali*_*ali 10 php laravel laravel-livewire

我有一张桌子productsjob_statuses使用这个包:laravel-job-status

队列作业完成后,有一个job_statuses名为statuspackage made this column 的列finished

所以我在products表中创建了一个名为job_status_id(relation with job_statuses)的列,只是为了将作业状态 ID 保存在产品表中,以查看此作业是否完成!

简单地,我创建了一个组件,Livewire用于在作业完成后刷新组件时刷新单个产品:

class ProductIndex extends Component
{
    public $product;


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

    public function render()
    {
        return view('livewire.merchant.product.index');
    }
}
Run Code Online (Sandbox Code Playgroud)

内部product-index组件:

@if ($product->job_status->status == 'finished')
  // show real image? 
@else
  // show loader 
@endif
Run Code Online (Sandbox Code Playgroud)

我的刀片:

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

如果状态已完成,如何刷新产品组件?

Qir*_*rel 22

您可以在组件中添加事件侦听器,然后从页面上的任何位置(甚至从 JavaScript)触发事件以刷新组件。

要添加侦听器以使组件自行刷新,只需将以下行添加到您的ProductIndex组件中。

protected $listeners = ['refreshProducts' => '$refresh'];
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

在 Livewire 组件中,您可以使用

protected $listeners = ['refreshProducts' => '$refresh'];
Run Code Online (Sandbox Code Playgroud)

您还可以通过执行从 JavaScript 发出事件

<script>
    Livewire.emit('refreshProducts')
</script>
Run Code Online (Sandbox Code Playgroud)

如果您想让队列在完成后触发该事件,您需要实现一些东西,要么轮询服务器以询问“作业是否完成”,然后触发该事件,或者您可以使用 Laravel Echo 作为 websocket。这将允许您触发和侦听来自 Livewire 生态系统之外的事件。

轮询

轮询时,不必为每次更新都发出事件,因为组件会不断刷新自身。

轮询是持续更新 Livewire 组件的最简单方法,它不需要像 Laravel Echo 这样的任何 websockets 集成。这意味着每 X 秒(默认为 2 秒),您的组件将向您的服务器发出 AJAX 请求,以获取其最新数据,并使用新数据重新呈现自身。

这可以通过使用wire:poll属性包装组件来轻松实现- 这是使用 5 秒的示例。

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
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,这意味着该组件的所有实例都将重新呈现自己并向服务器发出自己的 AJAX 请求以获取最新数据。您可能希望为所有项目创建一个“父”组件,从而只重新渲染 1 个单一组件。

广播和网络套接字

我假设你已经安装了 Laravel Echo。现在 - 要实现此广播功能,您首先需要创建一个事件。运行命令

php artisan make:event ProductStatusUpdated
Run Code Online (Sandbox Code Playgroud)

这将在您的app\Events文件夹中创建一个事件。根据您的需要对其进行自定义。运行命令后,它看起来像这样,

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

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

我们可以将频道从 更改PrivateChannel('channel-name')Channel('products'),这使我们可以在产品频道的Livewire 中收听它(您可以随意命名频道,也可以收听私人事件 - Livewire 文档中有相关文档,参考在这个答案的底部)。

所以这意味着broadcastOn看起来像这样

public function broadcastOn()
{
    return new Channel('products');
}
Run Code Online (Sandbox Code Playgroud)

接下来,在作业完成其工作并设置所有状态后,从 Laravel 触发该事件,使用

<script>
    Livewire.emit('refreshProducts')
</script>
Run Code Online (Sandbox Code Playgroud)

现在我们需要更新 Livewire 组件中的监听器,以便我们可以通过 Laravel Echo 实际监听该频道上的广播(而不是我们之前所做的 Livewire 事件)。

<div wire:poll.5s>
    <!-- The rest of your view here -->
</div>
Run Code Online (Sandbox Code Playgroud)

我们完成了!您现在正在使用 Laravel Echo 广播一个事件,Livewire 拦截并运行该事件。侦听器现在是一个键/值对,其中值仍然是组件中的方法名称($refresh如果您愿意,您仍然可以使用魔术操作),并且键channel,eventecho:.

资源: