Defining globals in Inertia is quick and easy. Let's look at adding and accessing globals alongside warnings and an alternative approach.
In this article, we're working with Laravel and Vue. But, regardless of your stack, you should be able to transfer the knowledge over!
Let's dive in.
To define globals in Inertia, head to the HandleInertiaRequests
middleware within your project.
Here, you'll find the share
method, which by default will look something like this:
public function share(Request $request): array
{
return [
...parent::share($request),
'auth' => [
'user' => $request->user(),
],
];
}
To add data that you want to be globally accessible to all of your Inertia pages and Vue (or other) components, just add to this array.
As an example, let's say we need to access product categories globally across our application:
public function share(Request $request): array
{
return [
...parent::share($request),
'auth' => [
'user' => $request->user(),
],
'categories' => Category::get()
];
}
Ideally, you'd wrap this in an API resource to control the structure of your data. But, for now, this will do.
There are several ways to access the globals you've defined in Inertia.
You can access your defined globals anywhere in your Vue components now by doing the following:
<div>
{{ $page.props.categories }}
</div>
$page
holds all of the information about the current Inertia page, including all the globals defined in HandleInertiaRequests
.
Since all your globals in HandleInertiaRequests
are shared as props, you can access them as you usually would other props that you've passed down:
<script setup>
const props = defineProps({
categories: Array
})
console.log(props.categories)
</script>
This is useful when you need immediate use of your props within the script section of your page. However, this won't work within child components, unless you explicitly pass down this data as a prop again.
This solution allows you to access globals in Inertia regardless of where you need them. Using usePage
, you can access globals in pages, child components, and even JavaScript files.
Here's what it looks like:
<script setup>
import { usePage } from '@inertiajs/vue3'
const page = usePage()
console.log(page.props.categories)
</script>
This is similar to using $page
within components (the first example we looked at) but works directly within our JavaScript code, too.
The issue with defining globals is that they're invoked for every request in your Inertia application. Generally, you want to avoid defining too many globals and rely on only passing down data when needed.
You can also define globals as lazy (or optional
in the most recent Inertia version) and then only load them when needed.
Here's the update to HandleInertiaRequests
:
public function share(Request $request): array
{
return [
...parent::share($request),
'auth' => [
'user' => $request->user(),
],
'categories' => inertia()->optional(function () {
return Category::all();
})
];
}
And here's how we can request this globally within a page or component:
<script setup>
import { router } from '@inertiajs/vue3'
router.reload({ only: ['categories'] })
</script>
<template>
<div>
{{ $page.props.categories }}
</div>
</template>
This delays loading the categories
global until we do a router.reload
call to specifically load in the categories
prop. Then, it'll be available in the template!
I rarely use this approach because it can make the source of your data unclear, and it starts to get cumbersome when you use router.reload
in multiple places.
When used sparingly, there's nothing wrong with this approach, but you may find it better to cache this data and always serve it within your globals rather than rely on reloading to hydrate and access globals.
There's one more approach, though...
What if we just made an HTTP request to an API-style endpoint instead of using globals to fetch the data we needed? That can make a lot of sense in the majority of scenarios!
Here's an example implementation. First, the controller:
class CategoryController extends Controller
{
public function index()
{
return Category::get()
}
}
Once again, you'll want to use API resources here to better structure your data.
Here's the route:
Route::get('/api/categories', [CategoryController::class, 'index'])
->name('api.categories.index');
And here's the request to fetch this data:
<script setup>
import { onMounted, ref } from 'vue'
const categories = ref([])
onMounted(() => {
fetch(route('api.categories.index'))
.then(response => response.json())
.then(data => categories.value = data)
})
</script>
<template>
<div>
{{ categories }}
</div>
</template>
With this approach, you can now independently fetch categories wherever needed.
The downside to this approach is that you won't benefit from server-side rendered content since you're fetching and hydrating after the page has loaded.
So, it's best not to use this method for anything you'd need available for SEO purposes.
Defining globals in Inertia is pretty easy, and we have a load of flexibility in how we do it.
Just remember not to add too many globals, and check that the globals you're defining are not too slow. Globals are loaded with every single page request, so you wouldn't want them slowing down every request.
We've also covered other methods you can use instead of globals, which may be more appropriate depending on how often you need to access the data or whether you need it immediately rendered on the page (e.g. for SEO).