diff --git a/resources/js/Pages/merging-props.jsx b/resources/js/Pages/merging-props.jsx index 2e0f5545..1e5ac7d4 100644 --- a/resources/js/Pages/merging-props.jsx +++ b/resources/js/Pages/merging-props.jsx @@ -5,8 +5,9 @@ export const meta = { title: 'Merging props', links: [ { url: '#top', name: 'Introduction' }, - { url: '#server-side', name: 'Server side' }, - { url: '#client-side', name: 'Client side' }, + { url: '#merge-methods', name: 'Merge methods' }, + { url: '#matching-items', name: 'Matching items' }, + { url: '#deep-merge', name: 'Deep merge' }, { url: '#client-side-visits', name: 'Client side visits' }, { url: '#combining-with-deferred-props', name: 'Deferred props' }, { url: '#resetting-props', name: 'Resetting props' }, @@ -18,89 +19,134 @@ export default function () { <>

Merging props

- By default, Inertia overwrites props with the same name when reloading a page. However, there are instances, - such as pagination or infinite scrolling, where that is not the desired behavior. In these cases, you can merge - props instead of overwriting them. + Inertia overwrites props with the same name when reloading a page. However, you may need to merge new data with + existing data instead. For example, when implementing a "load more" button for paginated results.

-

Server side

- To specify that a prop should be merged, you can use the Inertia::merge() or{' '} - Inertia::deepMerge() methods on the prop value. + Prop merging only works during partial reloads. Full page visits will always + replace props entirely, even if you've marked them for merging.

+

Merge methods

- Use merge when merging simple arrays, and deepMerge when working with nested objects - that contain arrays or complex structures, such as pagination objects. + To merge a prop instead of overwriting it, you may use the Inertia::merge() method when returning + your response.

+ input('page', 1); + $perPage = 5; + $offset = ($page - 1) * $perPage; + $tags = array_slice($allTags, $offset, $perPage); - // Get chunk of tags by page - $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), + ]); + }); + `} + /> +

+ The Inertia::merge() method will append new items to existing arrays at the root level. You may + change this behavior to prepend items instead. +

+ Inertia::merge($tags), - ]); - }); - `, - }, - { - name: 'Deep Merge', - language: 'php', - code: dedent` - Route::get('/users', function () { - $page = request()->input('page', 1); - $perPage = request()->input('per_page', 10); + // Prepend at root level... + Inertia::merge($items)->prepend(); + `} + /> +

+ For more precise control, you can target specific nested properties for merging while replacing the rest of the + object. +

+ append('data'); - return Inertia::render('Users/Index', [ - 'results' => Inertia::deepMerge(User::paginate($perPage, page: $page)), - ]); - }); - `, - }, - ]} + // Prepend to the 'messages' array... + Inertia::merge($chatData)->prepend('messages'); + `} /> +

You can combine multiple operations and target several properties at once.

+ append('posts') + ->prepend('announcements'); + // Target multiple properties... + Inertia::merge($dashboardData)->append(['notifications', 'activities']); + `} + /> +

+ On the client side, Inertia handles all the merging automatically according to your server-side configuration. +

+

Matching items

- During the merging process, if the value is an array, the incoming items will be appended to the - existing array, not merged by index. However, you may chain the matchOn method to determine how - existing items should be matched and updated. + When merging arrays, you may use the matchOn parameter to match existing items by a specific field + and update them instead of appending new ones.

Inertia::deepMerge($users)->matchOn('data.id'), + // Match posts by ID, update existing ones... + Inertia::merge($postData)->append('data', matchOn: 'id'); + + // Multiple properties with different match fields... + Inertia::merge($complexData)->append([ + 'users.data' => 'id', + 'messages' => 'uuid', ]); `} />

- In this example, Inertia will iterate over the users.data array and attempt to match each item by + In the first example, Inertia will iterate over the data array and attempt to match each item by its id field. If a match is found, the existing item will be replaced. If no match is found, the new item will be appended.

- - You may also pass an array of keys to matchOn to specify multiple keys for matching. - -

Client side

+

Deep merge

- On the client side, Inertia detects that this prop should be merged. If the prop returns an array, it will - append the response to the current prop value. If it's an object, it will merge the response with the current - prop value. If you have opted to deepMerge, Inertia ensures a deep merge of the entire structure. + Instead of specifying which nested paths should be merged, you may use Inertia::deepMerge() + to ensure a deep merge of the entire structure.

+ [ + ['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() was introduced before Inertia::merge() had support for prepending + and targeting nested paths. In most cases, Inertia::merge() with its append and prepend methods + should be sufficient. +

Client side visits

You can also merge props directly on the client side without making a server request using{' '}