inertia.jsのrouteでonly 使うと画面全体を更新せずに特定の情報だけ取ってこれますよね
しかし、バックエンドの書き方で全てのSQLが実行されてしまうことがあります
1. 😱 ダメなパターン(SQLが全部走る)
コントローラーで普通に値を渡している場合です。
return Inertia::render('Sales/Index', [
// ❌ only: ['supportOffices'] なのに、これも実行されちゃう!
'statistics' => Statistics::heavyCalculation(),
// ⭕️ 今回欲しいのはこれだけ
'supportOffices' => SupportOffice::all(),
]);
なぜ?
PHPは Inertia::render 関数を呼ぶ 「前」 に、引数である配列の中身を評価(実行)してしまうからです。
only でフィルタリングするのは、その 「後」 (Inertiaの処理の中)なので、時すでに遅しです。
2. 🚀 最適なパターン(Lazy Evaluation / 遅延評価)
これをするために、値ではなく 「関数(クロージャ)」 として渡します。
return Inertia::render('Sales/Index', [
// ✨ fn() => ... で囲む!
// Inertiaが「あ、これ今回は要らないな」と判断したら実行されない(SQL走らない)
'statistics' => fn() => Statistics::heavyCalculation(),
// あるいは Inertia::lazy() を使う
'heavyData' => Inertia::lazy(fn() => Heavy::get()),
'supportOffices' => fn() => SupportOffice::all(),
]);
なぜ?
fn() => ... で囲むと、その場では実行されず、「実行する準備」だけしてInertiaに渡されます。
Inertiaは、フロントから来た only: ['supportOffices'] というリクエストを見て、「statistics はリストに入ってないから、この関数は実行せずに捨てよう」 と判断します。
これで無駄なSQLを防げます!
バックエンドの動きのイメージ
あなたの router.post が送信された時の、サーバー内部の処理フロー図です。
まとめ:どう書けばいい?
supportOffices 以外のデータ(例えば filters や user 情報など)が軽いならそのままでいいですが、もし重い集計処理などがあるなら、コントローラー側で fn() => ... (アロー関数)で囲む ように変更してください。
// コントローラー例
return Inertia::render('Page', [
// 常に必要ならそのまま
'auth' => Auth::user(),
// 部分リロードで除外したい重い処理は fn() で囲む
'supportOffices' => fn() => SupportOffice::with('favorites')...,
'otherHeavyData' => fn() => ...,
]);
全てクロージャで囲んでしまって問題ありません✨