Laravelのくらげ？ Livewireをさわってみる

Laravel のデフォルトの Blade テンプレートを使って実装していると、コード量が増えるにつれ、可読性が落ちるのが気になっていました。
React や Vue などのコンポーネント指向の書き方に慣れているので、それっぽく書ける機能がないか調べたところ、Laravel のエコシステムの1つに「Livewire」というものがあったので、今回取り上げてみました。

![](https://laravel-livewire.com/favicon.ico)
## Livewire is 何 :confused:
公式サイトのファーストビューには以下のように書かれてます。
> Livewire is a full-stack framework for Laravel that makes building dynamic interfaces simple, without leaving the comfort of Laravel.

「Livewire を使えば、Laravel の扱いやすさをそのままに、動的なインターフェースを作れるぜ」的なことだと思います。

### 脱線。 語源を推測 :leaves:
開発者がどんな意図で名前をつけたのか気になってしまうので、推測してみました。

1単語ですが、語形成から`live`を`生きた`、`wire`を`線、ワイヤー`と分解して解釈すると、「クライアントとサーバーをリアルタイムで繋ぐワイヤー」みたいな意味合いでしょうか。
記事の後半で軽くいじってみますが、機能的には↑の意味合いで合ってそうでした。

とか思っていたんですが、そもそも`活動家、精力的な人`という意味の`live wire`という熟語があるらしく、ダブルミーニング的なことなのかなと。
その名の通り、こいつめちゃくちゃ働きます。

## Livewire 試運転 :red_car:
導入は Livewire のクイックスタートのままにやったので割愛します。
[Quickstart](https://livewire.laravel.com/docs/quickstart)
<br>
:cooking: ・・・
<br>
素朴な計数機の出来上がりです。

![スクリーンショット 2024-12-05 0.19.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353507/a42df178-917f-26d2-dc3f-70b0235611d0.png)

`app/Livewire/Counter.php`
```php
<?php

namespace App\Livewire;

use Livewire\Component;

class Counter extends Component
{
    public $count = 1;

    public function increment()
    {
        $this->count++;
    }

    public function decrement()
    {
        $this->count--;
    }

    public function render()
    {
        return view('livewire.counter');
    }
}

```

`resources/views/livewire/counter.blade.php`
```html
<!-- Counter コンポーネント -->
<div>
    <h1>{{ $count }}</h1>

    <button wire:click="increment">+</button>

    <button wire:click="decrement">-</button>
</div>
```

`App\Livewire`で作ったコンポーネントクラスで定義した
変数（`$count`）、
メソッド（`increment()`,`decrement()`）
が、`resources/views/livewire/counter.blade.php` で呼び出せます。
計数機くんは、クリックした時に`wire:click`で指定したメソッド名が呼び出されます。

## 仕組み
Livewire の実装はほどほどにして、どういう仕組みで動いているかの方が気になったので、そちらの路線で調べました。

まず、ページにアクセスした時の初期状態ですでに、Livewire を使っているコンポーネントに wire属性が付与されています。
`wire:snapshot` に `count:1`のような記述があるので、ここでデータを持っているようです。

```html
<div 
    wire:snapshot="{&quot;data&quot;:{&quot;count&quot;:1},&quot;memo&quot;:{&quot;id&quot;:&quot;x6b7a98mTcP8XrG0d4Im&quot;,&quot;name&quot;:&quot;counter&quot;,&quot;path&quot;:&quot;counter&quot;,&quot;method&quot;:&quot;GET&quot;,&quot;children&quot;:[],&quot;scripts&quot;:[],&quot;assets&quot;:[],&quot;errors&quot;:[],&quot;locale&quot;:&quot;en&quot;},&quot;checksum&quot;:&quot;274122539214fa2e25def11ec2670f57fef33dde471b2c05aef1d9832683a505&quot;}"
    wire:effects="[]"
    wire:id="x6b7a98mTcP8XrG0d4Im"
>
    <h1>1</h1>

    <button id="btn-increment" wire:click="increment">+</button>

    <button id="btn-decrement" wire:click="decrement">-</button>
</div>
```

次に、ボタンをクリックして、count の数を増減させ、開発者ツールのネットワークで動きを監視します。
すると、自サーバー内の `/livewire/update` に POST していました。

- ヘッダー
![スクリーンショット 2024-12-05 1.18.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353507/86565be1-d403-fe5f-6976-0e8af5e12dc7.png)

- ペイロード
![スクリーンショット 2024-12-05 1.19.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353507/e84c690d-dac6-0958-dabd-242cc557c9bb.png)

- レスポンス
![スクリーンショット 2024-12-05 1.19.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353507/c63b05b9-8c52-e0d3-7e58-7887cff6dbeb.png)

div タグに付与された wire:xxx 属性等の情報を渡して POST し、そのレスポンスとして wire:xxx に相当するデータと、コンポーネント自体の HTML が返ってきているようです。

更新されたHTMLを見てみると、レスポンスにある HTML に書き換わっているようで、データのみではなく、HTML自体がレスポンスとして返ってきていることに驚きました。

このリクエスト先（`/livewire/update`）は、Livewire の機能を追加すると自動でルーティングされます。

```
> php artisan route:list

  GET|HEAD   / ............................................................................................................... 
  GET|HEAD   counter .................................................................................... App\Livewire\Counter
  GET|HEAD   livewire/livewire.js ................................ Livewire\Mechanisms › FrontendAssets@returnJavaScriptAsFile
  GET|HEAD   livewire/livewire.min.js.map .......................................... Livewire\Mechanisms › FrontendAssets@maps
  GET|HEAD   livewire/preview-file/{filename} ....... livewire.preview-file › Livewire\Features › FilePreviewController@handle
  POST       livewire/update ............................. livewire.update › Livewire\Mechanisms › HandleRequests@handleUpdate
  POST       livewire/upload-file ..................... livewire.upload-file › Livewire\Features › FileUploadController@handle
  GET|HEAD   storage/{path} .................................................................................... storage.local
  GET|HEAD   up .............................................................................................................. 
```

このように、クライアントとサーバーを活発に通信してリアルタイムにデータを書き換えていくところが、live wire たる所以な気がしました。
何回も押すと、押す度リクエストが走るので、とても働き屋のくらげです。

## まとめ

Livewire で複雑なシステムを組んでいないので、パフォーマンス・速度等はなんともですが、どうやって値を書き換えているかのロジックを画面の情報から追ってみるのは、おもしろかったです。
コンポーネント指向っぽく Blade テンプレートを使って運用できるので、これまでやってきた Laravel プロジェクトの一部を書き換えてみたりして、この先検証できればなあと思います。

粗雑で拙い文章をここまで読んでいただきありがとうございました。

## 余談
Livewire を調べるとマスコット的に出てくるこいつ。（名前わからない）
![スクリーンショット 2024-12-05 0.01.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353507/85171e27-a96d-d774-6735-0a4c16ce08d5.png)

くらげ 🪼 だと思ってたんですが・・・
![スクリーンショット 2024-12-05 0.01.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1353507/7cde1c97-41be-5bf9-b500-78c2c0de2a64.png)
シュノーケルないと呼吸できないんかい。