【问题标题】:How to refresh the component after the queue job is finished?队列作业完成后如何刷新组件?
【发布时间】:2021-01-19 00:12:55
【问题描述】:

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

在队列作业完成后,job_statuses 中有一个名为 status 的包将创建此列 finished

所以我在products 表中创建了一个名为job_status_id 的列(与job_statuses 的关系),只是为了将作业状态ID 保存在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

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

【问题讨论】:

    标签: php laravel laravel-livewire


    【解决方案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 作为 websocket。这将允许您触发和侦听来自 Livewire 生态系统之外的事件。

    轮询

    当您进行轮询时,您不必为每次更新都发出事件,因为组件会不断刷新自己。

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

    这很容易通过使用wire:poll 属性包装组件来实现 - 这是一个使用 5 秒的示例。

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

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

    广播和网络套接字

    我假设您已经拥有installed 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,前缀为@987654345 @。

    资源:

    【讨论】:

    • 真的真的谢谢你!我需要安装 Websockets 吗?还是 Laravel Echo?
    • 如果您想使用 websockets,那么它们可以与 Livewire 完美集成。或者,您需要使用轮询(这会使 Livewire 每 X 秒重新渲染一次组件),我可以更新答案以包含一个示例。
    • 不,我不想使用 websockets,我的意思是。我的问题是,如果我必须安装 websockets,那么我将遵循第一种方式,如果不是,我将使用您提到的第二种方式!
    • 这两种方法各有利弊——轮询可以更容易集成,但这意味着向您的服务器发出的请求更多。不一定要产生太大影响,但您必须注意这一点(您可以检查浏览器中的网络选项卡以查看它们被触发)。
    • Laravel Echo 是一个 websocket,pusher 是一个单独的包,但与 Echo 结合使用非常方便。按照手册laravel.com/docs/8.x/broadcasting#installing-laravel-echo
    猜你喜欢
    • 2019-08-18
    • 2016-03-30
    • 1970-01-01
    • 2016-02-21
    • 1970-01-01
    • 2013-01-19
    • 2019-11-30
    • 1970-01-01
    • 2021-01-05
    相关资源
    最近更新 更多