Laravel8でLivewireの使い方を学ぶ

Laravel8では認証機能を担うJetstreamをインストールする際にLivewireかInertiaを選択する必要があります。どちらかのパッケージを選択するためには、Livewire、Inertiaの理解が必須になります。
選択時に違いがわからず悩まないように本文書ではLivewireについての基本的な動作を確認しながら、Livewireの理解を深めていきます。動作確認はLaravel8を使っています。
目次
Livewireとは
LivewireはJavaScriptのフレームワークのvue.jsやライブラリのReactと同様にページをリロードすることなくページ内容を更新することができます。通常はページをリロードすることなくページの更新を行うためにはJavaScriptでコードを記述する必要がありますが、LivewireではJavaScriptでコードを記述することなくPHPのみを利用してコードを記述することができます。バックエンドとの通信にはAjaxを利用していますがLivewireがバックエンドとの通信の処理を行ってくれるのでvue.jsやReactのようにfetch、axios、GraphQLなどを組み込んだAPI用のコードを記述する必要がありません。
Livewireでもライフサイクルフックやバインドという言葉が出てくるためvue.jsやReactと比較しながら考えることもできるのでvue.jsやReactの学習者の方が理解度も早いように思います。しかしLaravel8ではvue.jsの学習者はInertia(vue.jsを利用する)を選択する可能性が高いためLivewireを利用する機会はないかもしれません。vue.jsやReactの構文と同様にLivewireにも構文が多数存在するため使いこなすためには学習が必要となります。Bladeの構文が利用できるため、これまでのLaravelの知識が役に立ちます。
PHPのみでフロントエンドとバックエンドの処理を記述することができるため非常に効率的にアプリケーションを構築することが可能です。そのためPHPのみしか使用できない開発者がインタラクティブなフロントエンド部分の画面を作成することができます。その代わりLaravelのみでしか利用できないためLaravel以外でLivewireの技術を活用することができないという欠点もあります。
はじめてのLivewire
Livewireの動作確認を行うためにLaravelのインストールを行います。現在Laravelをインストールするとバージョンは8で、livewireはLaravelのインストール後にcomposerコマンドでインストールを行います。
% laravel new laravel8

Laravelのインストールが完了したら、livewireパッケージのインストールを行います。
% composer require livewire/livewire
Using version ^2.1 for livewire/livewire
livewireインストールが完了したらphp aritsan serveコマンドを実行して、resources¥viewsディレクトリの下にあるwelcome.blade.phpファイルの中身を削除し、以下のように書き換えます。
headタグの最後に@livewireStylesとbodyタグの閉じタグの前に@livewireScriptsを追加しています。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Livewire</title>
@livewireStyles
</head>
<body>
<h1>Hello Livewire</h1>
@livewireScripts
</body<
</html>
php artisan serveコマンドで開発サーバが起動するので127.0.0.1:8000にブラウザでアクセスするとHello Livewireが表示されます。

ブラウザ上にHello Livewireが表示できることが確認できたら、Livewireのコンポーネントを作成します。Livewireを利用してカウンターを作成するので名前をcounterとします。Livewireの作成はphp artisan make:livewireコマンドで行います。
% php artisan make:livewire counter
実行するとapp¥Http¥LivewireディレクトリにCounter.phpファイルとresouces¥views¥livewireディレクトリにビューファイルcounter.blade.phpファイルが作成されます。
Couter.phpファイルにはrender関数があり、view関数でCounter.phpファイルと一緒に作成されたビューファイルcounter.blade.phpファイルが指定されています。
namespace App\Http\Livewire;
use Livewire\Component;
class Counter extends Component
{
public function render()
{
return view('livewire.counter');
}
}
counter.blade.phpファイルには中身のないdivタグだけが記述されているので以下のようにh1タグを追加します。
<div>
<h1>初めてのLivewire</h1>
</div>
追加した内容を表示させるためにwelcome.blade.phpファイルにlivewireタグを以下のように追加します。
<h1>Hello Livewire</h1>
<livewire:counter>
ブラウザで確認し”初めてのLivewire”が表示されればLivewireは正常に設定されています。

変数を設定
今後はcounter.phpとcounter.blade.phpの2つのファイルのみ使って動作確認を進めていきます。
counter.blade.phpファイルに変数$countを設定します。
<div>
<h2>{{ $count }}</h2>
</div>
$counterを設定しただけでは定義をしていないのでエラーになります。$counterの定義はcounter.phpファイルで行います。
class Counter extends Component
{
public $count = 10;
public function render()
{
return view('livewire.counter');
}
}
初期値を10に設定すると設定通りブラウザ上に10が表示されます。ここまでの設定では通常のLaravelでの表示とは何も変わりません。

カウンターの作成
ボタンにクリックイベントを設定し、そのボタンをクリックするとcountの数字が増えるように設定を行います。vue.jsではクリックイベントを@click(or v-click)、reactではonclickと記述しますが、livewireではwire:clickと記述します。
<div>
<h2>{{ $count }}</h2>
<p><button wire:click="inc">+1</button></p>
</div>
clickイベントを設定後はcounter.phpファイルにclickイベントで指定したinc関数を追加します。
public $count = 10;
public function inc(){
$this->count++;
}
ブラウザからボタンをクリックするとページのリロードすることなくcountの数字が増えることが確認できます。

デベロッパーツールを見るとボタンをクリックする度に/livewire/message/counterにPOSTリクエストが送信されていることがわかります。

php artisan route:listでルーティングを確認するとPOSTのリクエスト先のlivewire/messageを確認することができます。

POSTリクエストを送信後にバックエンドからはcount.blade.phpファイルに記述している内容がそのまま戻されていることが確認できます。

input要素の追加
バインドを利用することでinput要素に入力した内容をそのままブラウザ上に表示を行うことができます。バインディングはwire:modelで行うことができます。
<input type="text" wire:model="message" >
messageをcounter.phpファイルで定義していない時に実行するとEXCEPTIONが発生しエラーの原因も画面上に表示されるのですぐに原因を特定することができます。

counte.phpファイルでmessageを定義するとエラーは発生しなくなります。
public $count = 10;
public $message;
画面に$messageの内容を表示できるように設定を行います。
<input type="text" wire:model="message" >{{ $message }}
input要素に文字列を入力するとそのまま入力した内容が表示されます。

debounceの設定
文字を入力するとバックグラウンドではajaxリクエストが行われています。リクエストの回数を下げるためにデフォルトでは入力を停止してから150ms後にajaxリクエストが行われます。設定値によってその時間を変更することができます。
設定を行うと入力後500ms後にajaxリクエストが行われます。
<input type="text" wire:model.debounce.500ms="message" >{{ $message }}

lazyの設定
デフォルトでは文字を入力後にajaxリクエストが行われていましたが、文字入力ではなくinputエリアから外れた時にajaxリクエストを行いたい場合はlazyを利用することができます。
<input type="text" wire:model.lazy="message" >{{ $message }}
deferの設定
debounceでは文字を入力してからajaxリクエストを送信するまでの時間、lazyではinput要素からカーソル外すとajaxリクエスト送信、deferでは入力後にボタンをクリックするとajaxリクエストを送信させることができます。
<input type="text" wire:model.defer="message" >{{ $message }}<br/>
<button wire:click="search">Search</button>
Searchボタンをクリックするとajaxリクエストが送信されますが、search関数を設定していないのでエラーが表示されます。search関数を設定すればエラーは表示されません。通常はボタンを押すとsearch関数を実行することになるので問題はありません。
if分の使い方
livewireでif文を利用する時はBladeの@ifをそのまま利用することができます。wire:ifといった構文はありません。livewireではvue.jsやReactとは異なり、bladeの構文を利用して制御できるものもあります。
if文を利用して文字を入力していない時としている時のメッセージを変えています。
@if(!$message)
<p style="color:red;font-weight:bold">文字を入力してください。</p>
@else
<p>文字を入力しました。</p>
@endif
文字を入力していない時は、赤字でメッセージが表示されます。

文字を入力するとページをリロードすることなくメッセージが変わります。

テーブルからのデータ取得
ここまでの処理ではcounter.phpファイルで定義した変数の内容を表示したり、数字を増やしたりするだけでした。次はLaravelのテーブルに保存されているデータの取得をlivewire内で行いテーブル内のユーザ情報の削除まで確認します。
データベース、テーブルの作成
データベースもテーブルも作成していないため、テーブルを作成する必要があります。本文書では、簡易的に作成ができるsqliteを利用してデータベースを作成します。Laravelのインストールディレクトリで下記のコマンドを実行し、データベースファイルを作成します。
% touch database/database.sqlite
.envファイルを使ってデフォルトのMySQLからsqliteへ接続するデータベースを変更します。接頭語にDB_がついているものでDB_CONNECTIONのみを残してsqliteを設定します。
DB_CONNECTION=sqlite
php artisan migrateコマンドを実行すると3つのテーブルが作成されます。
% php artisan migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated: 2014_10_12_000000_create_users_table (3.83ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated: 2014_10_12_100000_create_password_resets_table (2.00ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated: 2019_08_19_000000_create_failed_jobs_table (2.10ms)

Seedingを利用してにユーザテーブルにダミーデータを登録します。app¥database¥seedersを開いてコメントアウトされている行のコメントを外します。Laravel8からモデルファイルの保存先がApp¥Modelsになっているので注意してください。
use App\Models\User;
/* 略
public function run()
{
User::factory(10)->create();
}
php artisanコマンドを実行してダミーデータを作成します。
% php artisan db:seed
Database seeding completed successfully.
ユーザ一覧の表示
couter.blade.phpファイルを引き続き利用するため、下記のように更新します。bladeの@foreachを利用して$usersを展開します。このファイルだけ見るとLivewireの設定はありません。
<div>
<h2>ユーザ一覧</h2>
<ul>
@foreach($users as $user)
<li>{{ $user->name }}
@endforeach
</ul>
</div>
counter.phpファイルの中で$usersを取得する必要があります。取得はライフサイクルフックのmountを利用します。livewireのコンポーネントが初期化した直後に一度だけ実行され、render関数の前に実行が行われます。
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\User;
class Counter extends Component
{
public $users;
public function mount(){
$this->users = User::all();
}
public function render()
{
return view('livewire.counter');
}
}
ブラウザで確認するとユーザの一覧が表示されます。

ユーザの削除
ユーザ一覧の表示であれば通常のLaravelでのユーザ一覧の表示方法との違いがわかりません。@clickイベントを設定してユーザを削除する方法を確認します。
まずclickイベントを持つ削除ボタンの追加します。
<div>
<h2>ユーザ一覧</h2>
<ul>
@foreach($users as $user)
<li>{{ $user->name }} <button wire:click="delUser({{ $user->id }})">削除</button>
@endforeach
</ul>
</div>
ユーザ名の横に削除ボタンが表示されます。

clickイベントに設定したdelUser関数をCounter.phpファイルで設定します。filterを利用して削除ボタンを押した$idを持たない要素のみ取り出します。
public function delUser($id){
$this->users = $this->users->filter(function($value, $key) use($id){
return $value['id'] != $id;
});
}
ブラウザ上で削除ボタンを押すとページのリロードなしでユーザが削除できることを確認できます。削除ボタンを押すごとにユーザが削除されます。

しかし、この状態では再度ページにアクセスすると削除したユーザは再度表示されます。テーブル内のデータは実際に削除されていないためです。
Counter.phpファイル内でテーブル内のユーザを削除します。通常Laravelで利用するdeleteメソッドを使用します。
public function delUser($id){
$this->users = $this->users->filter(function($value, $key) use($id){
return $value['id'] != $id;
});
$user = User::find($id);
$user->delete();
}
deleteメソッド追加後、削除ボタンでユーザを削除するとページに再度アクセスすると削除したユーザの情報は表示されません。
非常にシンプルなコードを利用して動作確認を行ったのでLivewireがどのようなものか理解は進んだのではないでしょうか。