業務システムなどでよく求められる「確認画面」ですが、従来のControllerとBladeを使った画面遷移(マルチページ)では、入力データをセッションに一時保存して引き回す必要があり、実装が煩雑になりがちでした。
しかし、Livewire 3の「状態管理」を活用することで、セッションを使わずに驚くほどシンプルで保守性の高い確認画面を実装できます。本記事では、そのベストプラクティスを4つのステップで解説します。
コアとなる考え方:画面遷移から「状態の切り替え」へ
Livewireでの最大のポイントは、**「入力画面 → 確認画面とURLを遷移させるのではなく、1つのコンポーネントの中でフラグ(状態)によって表示するBladeを切り替える」**ことです。
$isConfirming という真偽値を持たせ、これが true なら確認用の表示を、 false なら入力フォームを表示する、というSPA(単一ページアプリケーション)的なアプローチをとります。
実装の4ステップ
Step 1: Form Object の活用(入力状態の集約)
Livewire 3 から標準となった Form オブジェクトを使って、入力データとバリデーションルールを切り出します。これにより、新規登録(Create)と編集(Edit)で同じロジックを使い回せます。
// app/Livewire/Forms/UserForm.php
namespace App\Livewire\Forms;
use Livewire\Form;
class UserForm extends Form
{
public string $name = '';
public string $email = '';
public function rules()
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|max:255',
];
}
}
Step 2: Livewireコンポーネントの実装(状態のトグル)
コンポーネント本体に $isConfirming フラグを持たせ、確認画面へ進むメソッドと、戻るメソッドを用意します。
// app/Livewire/UserCreate.php
namespace App\Livewire;
use Livewire\Component;
use App\Livewire\Forms\UserForm;
use App\Services\UserService;
class UserCreate extends Component
{
public UserForm $form;
public bool $isConfirming = false; // 確認画面の表示フラグ
// 確認画面へ進む
public function confirm()
{
$this->validate(); // バリデーションを実行
$this->isConfirming = true;
}
// 入力画面に戻る
public function back()
{
$this->isConfirming = false;
}
// 実際に保存する(Step 4で解説)
public function save(UserService $service)
{
$this->validate();
$service->createUser($this->form->all());
return redirect()->route('users.index')->with('status', '登録しました');
}
public function render()
{
return view('livewire.user-create');
}
}
Step 3: Bladeビューの部品化(Partial)と切り替え
確認画面専用のファイルを作るのではなく、「入力フォーム部品」と「確認表示部品」を別ファイルに切り出し、メインのBladeで @if を使って切り替えます。
メインのBlade (livewire/user-create.blade.php)
<div>
<h2 class="text-xl font-bold mb-4">
{{ $isConfirming ? '登録内容の確認' : 'ユーザー登録' }}
</h2>
<form wire:submit.prevent="{{ $isConfirming ? 'save' : 'confirm' }}">
@if (!$isConfirming)
@include('livewire.users.partials.form-fields')
@else
@include('livewire.users.partials.confirm-fields')
@endif
<div class="mt-6">
@if ($isConfirming)
<button type="button" wire:click="back" class="btn-secondary">戻る</button>
<button type="submit" class="btn-primary">この内容で登録する</button>
@else
<button type="submit" class="btn-primary">確認画面へ</button>
@endif
</div>
</form>
</div>
部品側のBladeは以下のようにとてもシンプルになります。これも新規・編集で使い回しが可能です。
入力用 (partials/form-fields.blade.php)
<div>
<label>お名前</label>
<input type="text" wire:model="form.name">
@error('form.name') <span>{{ $message }}</span> @enderror
</div>
確認用 (partials/confirm-fields.blade.php)
<div>
<label>お名前</label>
<p>{{ $form->name }}</p>
</div>
Step 4: ビジネスロジックの分離(Serviceクラス)
中〜大規模なシステムでは、Livewireコンポーネント内に直接DB保存の処理(User::create(...) など)を書くのは推奨されません。
トランザクション処理やメール送信などのビジネスロジックは、専用の Service クラスに切り分けます。
// app/Services/UserService.php
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\DB;
class UserService
{
public function createUser(array $data): User
{
return DB::transaction(function () use ($data) {
return User::create([
'name' => $data['name'],
'email' => $data['email'],
]);
});
}
}
これを Step 2 の save メソッドで依存注入(DI)して呼び出すことで、Livewireは「UIと入力の管理」に、Serviceは「データ処理」に専念でき、テストのしやすいクリーンなアーキテクチャになります。
まとめ
Livewire 3 を使えば、旧来のセッション管理の煩わしさから解放され、フロントエンドのJSフレームワーク(VueやReact)を使っているかのようなシームレスなUIをPHPの知識だけで構築できます。
- Form Object で入力をカプセル化する
-
$isConfirmingフラグで見た目を切り替える - Service クラス でビジネスロジックを分離する
この3つを意識するだけで、保守性が高く、チームメンバーにも読みやすいコードになるはずです。