🍣

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でフラッシュメッセージを表示するためには:

  1. HandleInertiaRequestsミドルウェアで share() メソッドを適切に設定する
  2. Vueコンポーネントでpropsからフラッシュメッセージにアクセスする

この設定を行うことで、Laravel従来のフラッシュメッセージの機能をInertia.jsと組み合わせて使用することができます。

参考リンク

Discussion