Props のマージ

Inertia はページを再読み込みする際、同じ名前の props を上書きします。しかし、場合によっては既存のデータに新しいデータをマージしたいこともあります。たとえば、ページネーションされた結果に対して「さらに読み込む」ボタンを実装する場合です。Infinite scroll コンポーネントは、内部で prop マージを使用しています。

Prop のマージは 部分的なリロード のときのみ動作します。フルページ遷移では、マージ対象としてマークされていても、props は常に完全に置き換えられます。

マージ方法

上書きではなくマージしたい場合は、レスポンスを返す際に Inertia::merge() メソッドを使用できます。

php
Route::get('/items', function () {
    // タグの静的配列...
    $allTags = [
        'Laravel', 'React', 'Vue', 'Tailwind', 'Inertia',
        'PHP', 'JavaScript', 'TypeScript', 'Docker', 'Vite',
    ];

    // ページごとにタグのチャンクを取得...
    $page = request()->input('page', 1);
    $perPage = 5;
    $offset = ($page - 1) * $perPage;
    $tags = array_slice($allTags, $offset, $perPage);

    return Inertia::render('Tags/Index', [
        'tags' => Inertia::merge($tags),
    ]);
});

Inertia::merge() メソッドは、ルートレベルにある既存の配列に新しい要素を追加(append)します。この挙動は、代わりに先頭へ追加(prepend)するよう変更できます。

php
// ルートレベルで末尾に追加(デフォルト)...
Inertia::merge($items);

// ルートレベルで先頭に追加...
Inertia::merge($items)->prepend();

より細かい制御が必要な場合は、オブジェクトの他の部分を置き換えつつ、特定のネストされたプロパティのみをマージ対象にできます。

php
// 'data' 配列のみに追加し、それ以外はすべて置き換える...
Inertia::merge(User::paginate())->append('data');

// 'messages' 配列の先頭に追加...
Inertia::merge($chatData)->prepend('messages');

複数の操作を組み合わせたり、同時に複数のプロパティを対象にすることもできます。

php
Inertia::merge($forumData)
    ->append('posts')
    ->prepend('announcements');

// 複数のプロパティを対象にする...
Inertia::merge($dashboardData)
    ->append(['notifications', 'activities']);

クライアント側では、サーバー側の設定に従って、Inertia がすべてのマージ処理を自動的に行います。

アイテムのマッチング

配列をマージする際、matchOn パラメータを使用すると、特定のフィールドで既存のアイテムと照合し、新しいアイテムを追加する代わりに更新できます。

php
// ID で投稿を照合し、既存のものを更新...
Inertia::merge($postData)->append('data', matchOn: 'id');

// 異なるマッチフィールドを持つ複数のプロパティ...
Inertia::merge($complexData)->append([
    'users.data' => 'id',
    'messages' => 'uuid',
]);

最初の例では、Inertia は data 配列を反復処理し、各アイテムを id フィールドで照合しようとします。一致するものが見つかった場合、その既存アイテムは置き換えられます。一致しない場合は、新しいアイテムが追加されます。

ディープマージ

どのネストされたパスをマージするかを指定する代わりに、Inertia::deepMerge() を使用して構造全体をディープマージすることもできます。

php
Route::get('/chat', function () {
    $chatData = [
        'messages' => [
            ['id' => 4, 'text' => 'Hello there!', 'user' => 'Alice'],
            ['id' => 5, 'text' => 'How are you?', 'user' => 'Bob'],
        ],
        'online' => 12,
    ];

    return Inertia::render('Chat', [
        'chat' => Inertia::deepMerge($chatData)->matchOn('messages.id'),
    ]);
});

Inertia::deepMerge() は、Inertia::merge() に prepend やネストパスの指定がサポートされる前に導入されました。ほとんどの場合、append や prepend メソッドを備えた Inertia::merge() で十分です。

クライアントサイドの訪問

クライアントサイド訪問 を使用すれば、サーバーリクエストを行わずにクライアント側で直接 props をマージすることもできます。Inertia は、prop の値を追加・先頭追加・置き換えするための prop ヘルパーメソッド を提供しています。

Deferred Props との併用

Deferred props をマージ可能な props と組み合わせることで、prop の読み込みを遅延させ、読み込み完了後にマージ可能として扱うことができます。

php
Route::get('/users', function () {
    $page = request()->input('page', 1);
    $perPage = request()->input('per_page', 10);

    return Inertia::render('Users/Index', [
        'results' => Inertia::defer(fn() => User::paginate($perPage, page: $page))->deepMerge(),
    ]);
});

Once Props との併用

マージ prop に once() 修飾子をチェーンすることで、データが一度だけ解決され、その後のナビゲーション間でクライアントに記憶されるようにできます。

php
return Inertia::render('Users/Index', [
    'activity' => Inertia::merge(fn () => $user->recentActivity())->once(),
]);

once props の詳細については、once props のドキュメントを参照してください。

Props のリセット

クライアント側から、prop をリセットしたいことをサーバーに伝えることができます。これは、ページネーションされたリストでユーザーが新しい検索クエリを入力した際など、新しいデータをマージする前に prop の値をクリアしたい場合に便利です。

reset リクエストオプションには、リセットしたい prop のキーの配列を指定します。

js
router.reload({
    reset: ['results'],
    // ...
})