inertiajs / inertia-laravel

The Laravel adapter for Inertia.js.
https://inertiajs.com
MIT License
2.01k stars 224 forks source link

[0.6.x] Add prop utilities #547

Closed timacdonald closed 11 months ago

timacdonald commented 11 months ago

Using nested layouts means we have a lot of "shared" data for each different level of layout.

We have:

  1. A global layout that has user specific data.
  2. A server layout that has server specific data.
  3. A site layout that has site specific data.

When you are looking at a site the user and server data is also provided via "shared" data.

Say you are looking at a site, on some endpoints we want to augment the server prop with some addition data.

We are currently using the following pattern a lot.

Inertia::render('MyPage', [
    'key' => fn () => array_merge(value(Inertia::getShared('key')), [
        'additional_data' => $server->additional_data,
        // ...
    ]),
]);

What is happening...

We are always wrapping our getShared call in a call to value as it may be a closure or an array and we need to unwrap it.

We then call array_merge to merge the shared with the new data.

We then wrap all of this back into a Closure to make sure it isn't sent on every future response.

The value helper does not support LazyProp shared data, so we would have to use special handling for lazy props.

We do this ~40 times throughout our application to merge in additional data.

This PR proposes adding 2 new utility functions for working with raw props and the same 2 with shared support specifically.

Note The following examples are in isolation and not how they would appear in an application - so keep that in mind when looking at them.

Inertia::resolveProp

This helper is essentially an Inertia specific version of the value helper with support for LazyProp.

Inertia::resolveProp('Tim');
// 'Tim'

Inertia::resolveProp(fn () => 'Tim');
// 'Tim'

Inertia::resolveProp(Inertia::lazy(fn () => 'Tim'));
// 'Tim'

Inertia::resolveShared

Inertia::share('name', 'Tim');

Inertia::resolveShared('name');
// 'Tim'

Inertia::share('name', fn () => 'Tim');

Inertia::resolveShared('name');
// 'Tim'

Inertia::share('name', Inertia::lazy(fn () => 'Tim'));

Inertia::resolveShared('name');
// 'Tim'

Note The closures for the second two examples have not been resolved by the merging process. They are still yet to be resolved.

Inertia::mergeProps

Inertia::mergeProps(['Tim'], ['Jaz']);
// ['Tim', 'Jaz']

Inertia::mergeProps(fn () => ['Tim'], ['Jaz']);
// fn () => ['Tim', 'Jaz']

Inertia::mergeProps(Inertia::lazy(fn () => ['Tim']), ['Jaz']);
// Inertia::lazy(fn () => ['Tim', 'Jaz'])

Note The closures for the second two examples have not been resolved by the merging process. They are still yet to be resolved.

Inertia::getSharedAndMergeProps

Inertia::share('names', ['Tim']);

Inertia::getSharedAndMergeProps('names', ['Jaz']);
// ['Tim', 'Jaz']

Inertia::share('names', fn () => ['Tim']);

Inertia::getSharedAndMergeProps('names', ['Jaz']);
// fn () => ['Tim', 'Jaz']

Inertia::share('names', Inertia::lazy(fn () => ['Tim']));

Inertia::getSharedAndMergeProps('names', ['Jaz']);
// Inertia::lazy(fn () => ['Tim', 'Jaz']

With this in place, we can more easily work with props and burn fn () => array_merge(value(Inertia::getShared( with fire...

Inertia::render('MyPage', [
-    'key' => fn () => array_merge(value(Inertia::getShared('key')), [
+    'key' => Inertia::getSharedAndMerge('key', [
        'additional_data' => $server->additional_data,
        // ...
    ]),
]);

It is also possible to make shared data eager for certain endpoints...

Inertia::render('MyPage', [
    'key' => Inertia::resolveShared('key'),
]);
timacdonald commented 11 months ago

Closing until I verify things.