Laravel8でLivewireを試してみる:ライフサイクル編

こんにちは、コバヤシです。
今回は前回書いた記事「Laravel8でLivewireを試してみる:実践編」に続いてLivewireのライフサイクルについて書いていきます。

tech.arms-soft.co.jp

ライフサイクルとは

簡単に言えば、ライブラリが読み込まれて、すべての処理が完了するまでの一連の流れがライフサイクルとなります。 このライフサイクルの中の各ポイントで、フックすることで、実行したいタイミングで処理を行うことが可能です。
Livewireにもライフサイクルにフック出来る箇所が設けられているので利用して制作していきます。

Livewireのライフサイクルフック

公式によれば以下が設定されています。

フック 説明
boot コンポーネントがインスタンス化された直後、他のライフサイクル・メソッド
が呼び出される前に、すべてのリクエストに対して実行します
mount コンポーネントがインスタンス化された直後、ただしrender()が呼び出される
前に1回実行します
hydrate コンポーネントがハイドレイトされた後、アクションが実行される、
またはrender()が呼び出される前に、後続のすべてのリクエストで実行します
hydrateFoo 名前が$fooのプロパティがハイドレイトされた後に実行します
dehydrate コンポーネントがデハイドレイトされる前、render()が呼び出された後に、
後続のすべてのリクエストで実行します
dehydrateFoo 名前が$fooのプロパティがデハイドレイトされる前に実行します
updating Livewireコンポーネントのデータが更新される前に実行します
(PHP内ではなく、wire:modelを使用)
updated Livewireコンポーネントのデータが更新された後に実行します
(PHP内ではなく、wire:modelを使用)
updatingFoo 名前が$fooのプロパティが更新される前に実行します。配列プロパティでは、
追加の$key引数があり、updatingArray($value, $key)の形式でこの関数へ渡し、
配列内の変更する要素を指定できます
updatedFoo 名前が$fooのプロパティが更新された後に実行されます。前記のように、
配列プロパティでは、追加の$key引数があります
updatingFooBar $fooプロパティのネストしたプロパティbarや、$fooBarか$foo_barなどの
マルチワードプロパティを更新する前に実行します
updatedFooBar $fooプロパティのネストしたプロパティbarや、$fooBarか$foo_barなどの
マルチワードプロパティを更新した後に実行します

readouble.com

ライフサイクルの順番

実際のライフサイクルの順番は、どうなっているのか見ていきたいと思います。

以下のような処理を書いて実行してみます。
ボタンをクリックするとカウントアップ、テキスト入力でコンポーネント内の変数とwire-modelで同期します。

<div>
    <h2>{{ $count }}</h2>
    <p><button wire:click="countup">カウントアップ</button></p>
    <h2>{{ $input }}</h2>
    <p><input type="text" name="input" wire:model="input"></p>
</div>
<?php
class IndexController extends \App\Http\Controllers\Controller
{
    public function index()
    {
        \Log::debug('start');
        return view('index');
    }
}
<?php
class Lifecycle extends Component
{

    public $count = 0;
    public $input;

    public function boot()
    {
        \Log::debug('boot');
    }

    public function mount()
    {
        \Log::debug('mount');
    }

    public function hydrate()
    {
        \Log::debug('hydrate');
    }

    public function hydrateCount()
    {
        \Log::debug('hydrate count');
    }

    public function hydrateInput()
    {
        \Log::debug('hydrate input');
    }

    public function dehydrate()
    {
        \Log::debug('dehydrate');
    }

    public function dehydrateCount()
    {
        \Log::debug('dehydrate count');
    }

    public function dehydrateInput()
    {
        \Log::debug('dehydrate input');
    }

    public function updating()
    {
        \Log::debug('updating');
    }

    public function updated()
    {
        \Log::debug('updated');
    }

    public function updatingCount()
    {
        \Log::debug('updating count');
    }

    public function updatingInput()
    {
        \Log::debug('updating input');
    }

    public function updatedCount()
    {
        \Log::debug('updated count');
    }

    public function updatedInput()
    {
        \Log::debug('updated input');
    }

    public function render()
    {
        \Log::debug('render');
        return view('livewire.lifecycle');
    }

    public function countup()
    {
        $this->count++;
        \Log::debug('countup');
    }
}

初期表示

まずは、表示しただけ。

local.DEBUG: start
local.DEBUG: boot
local.DEBUG: mount
local.DEBUG: render
local.DEBUG: dehydrate
local.DEBUG: dehydrate count
local.DEBUG: dehydrate input

Controllerでのviewの表示(start)、次にLivewireの表示となりboot、mountと続きrenderとなります。
概ね公式の通りですが、hydrateが無いのにdehydrateがあるのが解せないところです。

カウントアップ(メソッドによる変数更新)

次にカウントアップをしてみます。

local.DEBUG: boot
local.DEBUG: hydrate count
local.DEBUG: hydrate input
local.DEBUG: hydrate
local.DEBUG: increment
local.DEBUG: render
local.DEBUG: dehydrate
local.DEBUG: dehydrate count
local.DEBUG: dehydrate input

初回表示ではないので、mountは実行されていませんね。
又、今回はhydrateが行われています。 hydrateは、変数→コンポーネントの順番で実行され、dehydrateはコンポーネント→変数の順番で実行されることがわかります。

試しに、以下のように順番を変えてみたところ

<?php
    public $input;
    public $count = 0;

以下のようになりました。

local.DEBUG: boot
local.DEBUG: hydrate input
local.DEBUG: hydrate count
local.DEBUG: hydrate
local.DEBUG: countup
local.DEBUG: render
local.DEBUG: dehydrate
local.DEBUG: dehydrate input
local.DEBUG: dehydrate count

変数の宣言順に、処理が行われることが判明しました。

テキスト入力(wire-modelの同期による変数更新)

最後にテキストに入力して、wire-modelの同期を行います。

local.DEBUG: boot
local.DEBUG: hydrate count
local.DEBUG: hydrate input
local.DEBUG: hydrate
local.DEBUG: updating
local.DEBUG: updating input
local.DEBUG: updated
local.DEBUG: updated input
local.DEBUG: render
local.DEBUG: dehydrate
local.DEBUG: dehydrate count
local.DEBUG: dehydrate input

カウントアップ時には無かった、updating・updatedがあります。
公式に書かれているように、wire-modelの同期の時のみ実行されているのがわかりました。
コンポーネント→変数の順番で処理されていますね。

まとめ

ライフサイクルについて簡単にまとめてみました。
共通処理はboot、初期化処理はmountで行えば良さそうです。
初期表示時にhydrateが実行されないこと、変数の更新方法で実行されるフックが違うことには注意が必要ですが、 適切に処理できれば問題ないと思います。
ライフサクルのフックを活用していきましょう!

次回更新は2022年5月11日(水)を予定しています。