Laravel + Inertia.jsでフラッシュメッセージが表示されないredirect()->with('message')
Laravel + Inertia.jsでフラッシュメッセージが表示されない redirect()->with('message')
はじめに
LaravelでInertia.jsを使用している時に、リダイレクト時に->with()で渡したフラッシュメッセージが表示されなくて沼った
public function import(Request $request)
{
$input = $request->all();
return redirect()
->route('index')
->with('error', 'エラー発生');
}
このコードは一見問題なさそうに見えますが、Inertia.jsを使用している環境では、フラッシュメッセージが正しく表示されません。
なぜ動かないのか?
Inertia.jsはセッションデータに直接アクセスできません。
ここで重要なのは、->with()
の仕組みを理解することです:
->with()
メソッドは、Laravelの機能で、データを一時的にセッションに保存します。
従来のBladeテンプレートでは、このセッションデータに自動的にアクセスできましたが、Inertia.jsはPHPのセッションデータに直接アクセスできないため、フラッシュメッセージが表示されません。
つまり:
- Laravelのバックエンド:セッションにデータを保存 ✅
- Bladeテンプレート:セッションからデータを自動的に取得 ✅
- Inertia.js + Vue:セッションデータにアクセスできない ❌
そのため、Inertia.jsでフラッシュメッセージを使用するには、セッションデータをフロントエンドに明示的に渡す必要があります。
解決方法
1. HandleInertiaRequestsミドルウェアの設定
app/Http/Middleware/HandleInertiaRequests.php
に以下のように share()
メソッドを実装します:
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'flash' => [
'message' => fn () => $request->session()->get('message'),
'error' => fn () => $request->session()->get('error'),
'success' => fn () => $request->session()->get('success'),
],
]);
}
補足:なぜクロージャ(無名関数)を使用するのか?
フラッシュメッセージをクロージャとして定義する理由は、Inertia.jsのパーシャルリロード(部分的な更新)を最適化するためです。
// コントローラーでのフラッシュメッセージの設定 return redirect() ->route('index') ->with('error', 'エラー発生');
クロージャを使用する場合:
->with()
で設定された値のみが更新される('error' => fn () だけ)- リクエストのたびに値が評価され、最新のフラッシュメッセージを取得できる
- 他のページデータは再取得されない
- パフォーマンスが向上する
クロージャを使用しない場合:
- 毎回のページ遷移で値が固定され、古いフラッシュメッセージが残り続ける可能性がある
- 全てのページデータが再取得される可能性がある
- 不要なデータの再取得が発生する
これにより、SPA(Single Page Application)として動作する際でも、フラッシュメッセージが適切なタイミングで表示・消去され、かつ効率的なデータ更新が実現できます。
2. Vueコンポーネントでの表示
<script setup lang="ts">
type Flash {
error?: string
success?: string
message?: string
}
type Props {
flash: Flash
}
defineProps<Props>()
</script>
<template>
<div v-if="flash?.error" class="alert alert-error">
{{ flash.error }}
</div>
<div v-if="flash?.success" class="alert alert-success">
{{ flash.success }}
</div>
<div v-if="flash?.message" class="alert alert-info">
{{ flash.message }}
</div>
</template>
まとめ
Inertia.jsでフラッシュメッセージを表示するためには:
- HandleInertiaRequestsミドルウェアで
share()
メソッドを適切に設定する - Vueコンポーネントでpropsからフラッシュメッセージにアクセスする
この設定を行うことで、Laravel従来のフラッシュメッセージの機能をInertia.jsと組み合わせて使用することができます。
Discussion