🐕

Laravel Livewireでのイベント呼び出し

2024/06/02に公開

Laravel Livewireでのイベント呼び出し方法がバージョン2と3で変更点がいくつかあるため、呼び出し方についてまとめてみました。

イベント呼び出しについて

  • コンポーネントに定義されたイベントを呼び出す方法。
  • 他のコンポーネントのイベントを一斉に呼び出したり、特定のコンポーネントのみイベント呼び出したりできる。

バージョン3での実装の仕方

呼び出すイベント

Livewireコンポーネント内に呼び出したいイベントを追加します。
ここではModalコンポーネントにopenModal()イベントを追加します。

バージョン3ではLivewire\Attributes\Onをインポートし、呼び出す際のイベント名を指定します。

Modal.php
namespace App\Livewire;

use Livewire\Component;
// インポートする
use Livewire\Attributes\On;

class Modal extends Component
{
    public bool $is_show = false;

    // #[On()]でイベント名を設定する
    #[On('openModal')]
    public function openModal()
    {
        $this->is_show = true;
    }
}

イベントを呼び出す

バージョン2ではemit()メソッドを呼んでいましたが、バージョン3ではdispatch()メソッドでイベントを呼び出します。

Button.php
namespace App\Livewire;

use Livewire\Component;

class Button extends Component
{
    public function callModal()
    {
        // イベント名を指定して呼び出す
        $this->dispatch('openModal');
    }
}

注意点として、ページ上の全てのコンポーネントのイベントが呼び出される点に気を付けてください。
上記の例だとButtonコンポーネント以外にもopenModalイベントが定義されていた場合、どちらのコンポーネントのイベントも呼び出されます。

別のコンポーネントのイベントを呼び出す

例えばButtonコンポーネントからModalコンポーネントのイベントのみを呼び出したい場合、->to()で呼び出し対象のコンポーネントを指定することができます。

Button.php
namespace App\Livewire;

use Livewire\Component;

class Button extends Component
{
    public function callModal()
    {
        // ModalコンポーネントのopenModalイベントを呼び出す
        $this->dispatch('openModal')->to(Modal::class);

        // こちらの書き方でも呼び出しできる
        $this->dispatch('openModal')->to('modal');
    }
}

複数のコンポーネントの中の特定のコンポーネントのみイベントを呼び出す

例えば下記のようにユーザー一覧を表示するような管理画面があり、メール購読欄内に2つのコンポーネントが並んでいるとします。
左側のコンポーネントは現在メール購読する・しないどちらが設定されているかを表示するコンポーネントがあり、(ここではSubscriptionType.phpとします)
その右隣にメール購読する・しないを変更するためのボタンコンポーネントが人数分あるとします。

変更ボタンを押した際、該当するユーザーの表示のみ更新したいのですが、ただdispatch()でイベントを呼び出すと全てのユーザーのコンポーネントのイベントが呼び出されてしまいます。
一覧に表示されているのが2人程度でしたらそこまで影響少ないかもしれませんが、100人など人数が多い場合その分だけ無駄にイベントが呼ばれることとなってしまうため、複数コンポーネントのうち特定のコンポーネントにのみイベントを呼び出せるようにします。

動的なイベント名に変更する

呼び出したいイベントの#[On()]をイベント名.{条件}のような形式に変更します。
例えば今回はUserクラスを持たせ、UserクラスのIDで判別できるようにします。

SubscriptionType.php
namespace App\Livewire;

use App\Models\User;
use Livewire\Component;
use Livewire\Attributes\On;

class SubscriptionType extends Component
{
    public User $user;

    // user.idが合致している場合のみ呼び出される
    #[On('update.{user.id}')]
    public function update()
    {
        $this->dispatch('$refresh')->self();
    }
}

動的なイベントを呼び出す

先ほど動的なイベント名にしたイベントを呼び出します。

Button.php
namespace App\Livewire;

use App\Models\User;
use Livewire\Component;
use Livewire\Attributes\On;

class Button extends Component
{
    public User $user;

    #[On('change')]
    public function change()
    {
        // dispatchに渡すイベント名にidを追加する
        $event = 'update.' . $this->user->id;
        $this->dispatch($event)->to(SubscriptionType::class);
    }
}

これでuser.idが合っているコンポーネントのみイベントを呼び出すことができました。

バージョン2での実装の仕方

Livewireバージョン2では呼び方が異なるため、バージョン2での実装方法についても触れておきます。

イベントを呼び出す

バージョン2ではemit()メソッドでイベントを呼びます。

Button.php
namespace App\Livewire;

use Livewire\Component;

class Button extends Component
{
    public function callModal()
    {
        // イベント名を指定して呼び出す
        $this->emit('openModal');
    }
}

別のコンポーネントのイベントを呼び出す

Button.php
namespace App\Livewire;

use Livewire\Component;

class Button extends Component
{
    public function callModal()
    {
        // ModalコンポーネントのopenModalイベントを呼び出す
        $this->emitTo('modal', 'openModal');
    }
}

呼び出される側のイベントは$listenersに他のコンポーネントから呼ばれる際のイベント名を設定します。

Modal.php
namespace App\Livewire;

use Livewire\Component;

class Modal extends Component
{
    public bool $is_show = false;

    // 他のコンポーネントから呼び出すイベントを設定する
    protected $listeners = ['openModal'];

    // またはメソッド名とは異なるキーにすることもできる
    protected $listeners = ['open' => 'openModal'];

    public function openModal()
    {
        $this->is_show = true;
    }
}

複数のコンポーネントの中の特定のコンポーネントのみイベントを呼び出す

動的なイベント名に変更する

バージョン2の場合、まず呼び出す側でイベントリスナーを動的に名前付ける必要があります。
その場合、$listenersではなくgetListeners()を使ってイベントリスナーを設定します。

SubscriptionType.php
namespace App\Livewire;

use App\Models\User;
use Livewire\Component;

class SubscriptionType extends Component
{
    public User $user;

    // $listenersの代わりにgetListeners()を使用する
    protected function getListeners()
    {
        return ['update.' . $this->user->id => 'update'];
    }
}

動的なイベントを呼び出す

先ほど動的なイベント名にしたイベントを呼び出します。

Button.php
namespace App\Livewire;

use App\Models\User;
use Livewire\Component;

class Button extends Component
{
    public User $user;

    public function change()
    {
        // emitToに渡すイベント名にidを追加する
        $this->emitTo('subscription-type', 'update.' . $this->user->id);
    }
}

参考

Upgrade Guide | Laravel Livewire
Events | Laravel Livewire

Discussion