Improve page responsiveness with lazy loading in InertiaJS
Part of the attractiveness of A javascript single page app vs. the more traditional server-rendered ones is a perception of speed for the users - page loads and navigation can feel instantaneous while presenting loading states to the user to show them that something's happening, rather than just waiting for the entire page to load.
We're currently using InertiaJS, which allows us to marry all the best parts of a single page app with the server-side routing and data management benefits of a more traditional javascript app.
Now normally you'd pass your data to Inertia by passing data in a similar way you'd pass it to blade views:
And in our frontend component:
Simple right? But what if $posts
is a complicated query takes 3-4 seconds to pull from the database? Laravel won't even send anything to the browser until it's completed that query. Your users will see a blank screen, or even worse, it'll just look like they've stayed on the same page and nothing has happened.
Now normally, we'd fix this by returning the empty page skeleton, and then making an AJAX request - usually with something like Axios, to retrieve our data.
This approach has a few drawbacks:
- You usually have to register another, separate route to make the request to which means you have to write a separate controller method or handler.
- The new controller or handler doesn't automatically have the context from the current page load, so you have to push that context (any query arguments or route parameters), in the ajax request.
- All of that is extra code to maintain and test.
Lazy loading solves this by allowing you run a partial reload on data that wasn't included at all during the initial page load. The Inertia documentation has a great guide on how to set up data for lazy loading:
You can see the big difference with the third approach is that it's "NEVER included on the first visit". This makes your initial page load much faster, and allows you to set up a spinner, skeleton, or loading component of your own to show that data is being loaded in.
To do this, first, wrap any large datasets or queries in the Inertia::lazy()
function:
Now, because this is lazy-loaded, in our javascript component, the prop will have whatever initial value we set. Here, i'm setting it as undefined
by default.
We're doing a few things here:
- Defining our prop as
undefined
by default, but you could also make this an empty array if you like. - When the component is mounted, we're making a partial reload call using
Inertia.reload
. - Checking for the state of the
posts
variable, and if it'sundefined
, we're showing a loader.
And that's it! You can use this approach to load in data when it's needed, not just on the mount hook.
For example, you could pair it with the Intersection API to detect when an element enters the brower viewport and fire the partial reload function.