【高速検索】Laravel × Livewire でインクリメンタルサーチ

こんにちは!JavaScript が苦手なWebサービス事業部の白井です。
今回は筆者と同じような方に向け、JavaScript をほとんど書かず、普段のサーバーサイドの開発の要領で実装できる、Livewire についてご紹介したいと思います。
実際にLaravelとLivewireを使用して、簡易的なインクリメンタルサーチ機能の実装をしていきますのでご覧ください!
インクリメンタルサーチって?
インクリメンタルサーチ(Incremental Search)は逐語検索、逐次検索とも呼ばれ、ユーザーが入力フィールドに文字を入力する度に、自動的に検索結果がフィルタリングされて表示される検索機能のことを指します。
つまり、文字を入力するたびに検索結果がリアルタイムで絞り込まれ、動的に検索結果が表示される仕組みのことを言います。
普通の検索では文字を入力→検索→検索結果表示という流れだと思いますが、このインクリメンタルサーチでは文字を入力する度に検索結果を返してくれるのです!
Livewireとは
Livewire とは、Laravel をベースにした PHP で書かれた動的なコンポーネントライブラリのこと。
PHP でサーバーサイドのコードを記述しながらも、リアルタイムなUIの更新やインタラクティブな機能を実装するための手段を提供してくれます。
したがって Livewire を使うことで、JavaScript をほとんど書かずにリアクティブなWebアプリケーションを開発することが可能となるわけです。
今回はその Livewire を Laravel で使用してインクリメンタルサーチ機能を実装していきましょう!
バージョン情報
本記事のフレームワークやライブラリのバージョンについては下記の通りとなっています。
Laravel 11.1.1 Livewire 3.4.9 PHP 8.3.4
いざ実装
Livewire 自体の導入方法は至って簡単です。
Laravel のプロジェクトの composer.json があるディレクトリで
composer require livewire/livewire
と composer を使用してインストールするだけです。
Livewire をインストールできたら、次にインクリメンタルサーチを行うコンポーネントの作成に入ります。
今回はユーザーの検索を行いたいので、下記コマンドでユーザー検索のコンポーネントを作成します。
php artisan make:livewire UserSearch

コマンドを叩いたら UserSearch クラスと view が作成されたのを確認できると思います。
次にロジッククラスを実装します。
今回はフォームに名前かメールアドレスを入力したら、どちらかにヒットする検索結果が返ってくるようにします。
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Services\User\ListUsersService;
class UserSearch extends Component
{
// 検索文字列を保持するプロパティ
public $search = '';
// コンポーネントの描画を担当するメソッド
public function render(ListUsersService $listUsersService)
{
// ユーザー一覧を取得し、検索文字列に基づいてフィルタリング
$users = $listUsersService->list()->filter(function ($user) {
return str_contains($user->name, $this->search) || str_contains($user->email, $this->search);
});
// ビューを描画し、フィルタリングされたユーザー一覧を返す
return view('livewire.user-search', ['users' => $users]);
}
}
検索文字列を保持するプロパティとして $search を定義し、ユーザーが検索フォームで入力した文字がこのプロパティに格納されます。
ListUsersService からユーザーの一覧を取得し、ユーザーの name もしくは email でフィルタリングし、返ってきた結果をコンポーネントの view に渡すという流れになっています。
次に view 部分を実装します。
<div>
{{--フォームで入力した値が$searchプロパティにリアルタイムで反映され、100ミリ秒後にコンポーネントを描画--}}
<input type="text" class="form-control" placeholder="名前orメールアドレスで検索" wire:model.live.debounce.100ms="search">
{{--$searchプロパティが空でない場合にのみ、テーブル形式で検索結果を表示--}}
@if($search)
<table class="mt-3 w-100">
<thead>
<tr>
<th scope="col">名前</th>
<th scope="col">メールアドレス</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@forelse($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->email }}</td>
<td>
<button type="button" class="btn btn-success" wire:click="detail({{ $user->id }})">詳細</button>
</td>
</tr>
{{--検索結果が存在しない場合--}}
@empty
<tr>
<td colspan="3" class="text-center">一致する検索結果がありません。</td>
</tr>
@endforelse
</tbody>
</table>
@endif
</div>
詳細な説明は省きますが、フォームに Livewire のデータバインディングを使用し、ユーザーがフォームに入力を行ったらテーブル形式で検索結果が返ってくるようにします。
これでユーザー検索を行うコンポーネントが完成したので、最後に blade ファイル内の読み込みたい箇所で
@livewire('user-search')
@livewireScripts
と上記のディレクティブを読み込めば今回作成したコンポーネントを読み込んでくれます!
完成
お疲れ様でした。実装はこれだけです!
今回実装したインクリメンタルサーチ機能は下記のような感じになります。
いかがでしたでしょうか?
今まで JavaScript を使用して実装していたものが、Livewire 使うだけでこんなに簡単に実装をすることができるのです。
今回は名前とメールアドレスだけの簡単な検索機能の実装でしたが、ユーザーの属性や絞り込み検索を追加して検索機能を強化してもいいですし、出力された検索結果をイベントリスナーでイベントをリッスンし、別の処理を走らせても面白いと思います!
まとめ
普段のサーバーサイドの開発の要領で、JavaScript を使わずに簡単に実装できるのは、Livewire ならではだと思います。
唯一デメリットを挙げるとしたら、Laravel でしか使えないことくらいでしょうか。
ただ、Laravel で開発をしている方は、一度試してみて損はないと思います!それくらい楽で楽しいライブラリだと思います。
それではよき Laravel ライフを!
4