まだJSで消耗してるの？LaravelのLivewireでSPA開発

# タイトルで釣りました（[1年ぶり2度目の犯行](https://qiita.com/namizatork/items/801da1d03dc322fad70c)）

煽ってごめんなさい
JavaScript大好きだよ（ﾎﾝﾄﾀﾞﾖ）

## はじめに

この記事は [弁護士ドットコム Advent Calendar 2020](https://qiita.com/advent-calendar/2020/bengo4com) の記念すべき1日目の記事です🎉

## Livewireとは

こんなことを思った事はないだろうか、、
なぜ簡単なWebアプリケーションを作りたいだけなのにVueやReactを別で用意してJSを書かないといけないのか...
ワイはPHPerなんや...JSなんて書きたくないんや....

そんな贅沢な悩みを持つPHPerを解決に導くツールこそ **Livewire** なのだ！！

### それっぽい説明

LivewireとはBlade（Laravelの標準Viewテンプレート）を用いて、JavaScriptを記述せずにSPAを実現できるライブラリのことです。
これまでの様にフロントエンドにVueやReactなどフレームワークを選定する必要がなくなり、
バックエンドはもちろんフロントエンドもLaravelだけで開発が可能になりました。

> LivewireはLaravelの標準ライブラリではありません。
> Laravelで認証機能を担う [Jetstream](https://jetstream.laravel.com/1.x/introduction.html) を使用する際に、
> View部分をLivewireかInertiaを選択する必要があるのでその際にLivewireを選択する。
> または直接インストールして使用する方法があります。

自分で書いといてアレだけどピンとこないと思う

## とはいえ実装方法

上記の~~どこにでも落ちてそうな~~説明ではいまいちイメージ出来ないと思うので、
公式のデモコードで実装方法を確認してみます。

デモコードの内容は <input> 要素に名前を入力して一致した名前をリアルタイムで下に表示するというよくあるやつ

![1l6nc-5wawf.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/040cc4f7-1545-0ee7-0c4c-c3258d3acb17.gif)

> Userのテストデータが用意されている前提で進めます！

### コンポーネント（ロジック部分）

従来の Controller の様に使用します。
Laravel知ってる人なら分かると思うけど、この辺は記述に変わったところはなく、
プロパティの `$search` の値を検索条件として、Usersテーブルの `name` に一致するデータをViewに返しているだけです。

```php:App\Http\Livewire\SearchUsers.php
<?php

namespace App\Http\Livewire;

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

class SearchUsers extends Component
{
    public $search = '';

    public function render()
    {
        return view('livewire.search-users', [
            'users' => User::where('name', $this->search)->get(),
        ]);
    }
}
```

### コンポーネント（View部分）

View部分は<input> 要素に `wire:model="search"` という記述以外変わったところはなさそう
ロジック部分から受け取った値 `users` から `name` のみを表示している。

```php:resources/views/livewire/search-users.blade.php
<div>
    <input wire:model="search" type="text" placeholder="Search users..."/>

    <ul>
        @foreach($users as $user)
            <li>{{ $user->name }}</li>
        @endforeach
    </ul>
</div>
```

### コンポーネントを呼び出す

最初から用意されている `welcome.blade.php` にて先ほど作成したコンポーネントを呼び出してみます！ `@livewire('search-users')`の部分が該当部分です。

```php:welcome.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Livewire</title>
    @livewireStyles
</head>
<body>
    @livewire('search-users')
    @livewireScripts
</body>
</html>
```

なんとこれだけで終わりです！
Laravel知ってる人なら簡単ですよね？

## Livewireを使えばこんな事も簡単

welcome.blade.phpでコンポーネントを呼び出す前提でデモを実装しています。

### 1. ファイルアップロード

リアルタイムでファイルアップロード機能を実装したいなぁ
だけdなんだかんだでJSでAjax書いたりと色々大変だしなぁ...

**Livewire** なら `WithFileUploads` をuseしてstore()で保存するだけ！

![chthl-cy304.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/69e31966-91f2-fcf1-ebf8-271b32a6fb8f.gif)

`ロジック部分`

```php:UploadPhoto.php
<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Livewire\WithFileUploads;

class UploadPhoto extends Component
{
    use WithFileUploads;

    public $photo;

    public function save()
    {
        $this->photo->store('photos');
    }
}
```

`View部分`

```php:upload-photo.blade.php
<div>
    <input type="file" wire:model="photo">
    <button>Save Photo</button>
</div>
```

### 2. もっと読み込む

もっと読み込むってボタンを押したら非同期で一覧データを読み込むの作りたいなぁ
でもJS書くのめんどくさいなぁ...

**Livewire** なら `wire:click` でイベントを受け取って取得処理するだけで簡単

![1wldn-0gui9.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293438/0bc22f60-c066-4122-4e02-e9c2f0cd9c97.gif)

`ロジック部分`

```php:LoadMore.php
<?php

namespace App\Http\Livewire;

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

class LoadMore extends Component
{
    public $amount = 5;

    public function load()
    {
        $this->amount += 5;
    }

    public function render()
    {
        return view('livewire.load-more', [
            'users' => User::take($this->amount)->get()
        ]);
    }
}
```

`View部分`

```php:load-more.blade.php
<div>
    <table>
        <tr>
            <th>名前</th>
            <th>Email</th>
        </tr>
        @foreach ($users as $user)
            <tr>
                <td>{{ $user->name }}</td>
                <td>{{ $user->email }}</td>
            </tr>
        @endforeach
    </table>
    <button wire:click="load">もっと読み込む</button>
</div>
```

最初のデモと処理的な物はほとんど一緒なので詳細は省く

## メリデメ

### Livewireを使うメリット

- 普段からLaravel使ってる人なら低い学習コストで実装できる
- 簡単なwebアプリケーションの実装ならJSよりこっちの方が楽（な気がする）
- JSのこと気にしないで書けるのは割とストレスフリー
- マスコットが可愛い

### Livewireを使うデメリット

- Laravel知らない人には学習コストが高い
- Laravel依存ライブラリなので改修する時のコストが高そう
- JSのフレームワークの様に知識的な汎用性に欠ける
- 記事が少ないので詰まる ≒ 死

## 所感

多分複雑なことをやろうとすると結局は内部で使用している `Alpine.js` を使うことになると思うの...
PHPerの理想郷はまだ先なのかもしれない...。

## 最後に

弁護士ドットコムでは **Livewire** を使う予定は皆無だけど
一緒に働く仲間を募集しています🧑‍💻

[弁護士ドットコム株式会社 エンジニア採用情報](https://hrmos.co/pages/bengo4/jobs/0009602)

---

`12/02` はReactといえばの「プログラミングをするパンダ」さんの担当日です
[弁護士ドットコムライブラリーのフロントエンドのアーキテクチャ（Next.js + TypeScript）](https://panda-program.com/posts/bengo4com-library-frontend)