Currently the navigation behavior with Nuxt is the following:
This is not ideal UX-wise. Even when I make efforts to make my page quite fast and enable the loading indicator, the load times are inconsistent, and the page feels broken and frozen upon clicking a link as a result.
I think a better behavior would be the following:
This way, we mitigate the problems significantly by taking advantage of two common patterns: offering immediate feedback after user interaction, and using exit transition duration to hide part of the loading time.
I don't think there's need to take away the current behavior, but to rather a new alternative as an option, and also consider using it as a default. I'm sure I'm not the first one thinking of this but could still find no issues or discussion around it. Also whether the route visibly updating immediately or during the transition phase... probably not that big a deal, but immediate feedback is good.
I'm not really up-to-date on all the tech behind the navigation logic, but I think this could drastically improve the perceived performance of Nuxt sites, hiding most of the page loads behind transitions.
EDIT:
A couple more points to clarify:
asyncData
to other lifecycle hooks, in which case I get detailed control over my loading and wait time behavior. But I of course rely on asyncData
for a reason, which is I want my prerendered pages to have the content available.Of course it would be awesome to have even more controls over how long loading times are handled between transitions, or even rendering (some) pages before asyncData completes in SPA mode only (i.e. allowing devs to write custom loading behavior while still staying server-render-friendly).
One point about the route updates.
Let's say I have a sidebar panel with a menu that I want to close as the user clicks on any link. I can attach a watcher to current route and close it upon update. It he route update is immediate, user will get immediate feedback as well. Right now I have to either explicitly attach the close behavior to every link in my menu, or force the user to wait the page to load while the menu is open, after which the menu will close.
So if the route updates are immediate, I can orchestrate things better so that transitions related to the desired route can start playing as soon as possible. This is kinda analogous to how web works anyway, meaning the DOM reflects the desired state and the browser will transition elements if they are not where they ought to be.
@eiski
You could fetch the data in mounted:
mounted() {
fetch('...').then((data) => {
Object.assign(this, data);
})
}
You could fetch the data in mounted:
This is of course true, but then my app becomes basically just a normal SPA and not an SEO-friendly universal/prerendered app - which is the reason I use this awesome, awesome project! I'll edit the original post to highlight this.
Is this a duplicate of https://github.com/nuxt/nuxt.js/issues/2568 ?
Is this a duplicate of #2568 ?
I knew I wasn't the first one!
It's close but not really an exact duplicate. I'd be happy to see the changes proposed there, but I'm proposing a different solution here (to the same problem). I think both can coexist though.
My proposal was basically a new transition mode, meaning old page is transitioned out without delay but asyncData is still respected for the new page. This could just be a catch-all default behavior you could enable for your entire application in nuxt.conf.js
with one parameter or maybe a function that resolves per route.
I do see the need for more fine-grained loading handling for specific views, but with my proposal you can still write pages as you do now, meaning you don't have to cover that additional isLoading
state.
You could also use a plugin for client side. Which fetches the data after route transition:
export default ({app}, inject) => {
app.router.afterEach(() => {
// Get the current page and call a load method
// Commit it to the store, or apply it to the pagecomponent
})
})
And use a middleware server side:
export default ({ app, req, res, route, store, redirect, isHMR }) => {
if (process.server) {
// Get the current page and call a load method
// Commit it to the store, or apply it to the pagecomponent
return fetchPromise; // This is important
}
})
You could also use a plugin for client side. Which fetches the data after route transition:
Yeah I can see how that could work. I could set up named page transitions and use a mixin for every page component that would introduce generic loading state behavior for a new page that is still waiting for page data to be there, and transition itself in once done.
I guess I would be able to reach the behavior like this, but this does require a lot of workarounds, careful architecture and very detailed knowledge of how Nuxt works and careful orchestration of design elements and custom transitions to make it work. I think I'll try messing around with this kind of approach to see if I can get it working, but I don't think it's a good solution for the general public.
I would invert 5 and 6.
Transitioning to our new page would leave us handle some placeholder blocks (for example) until data is done loading.
Most helpful comment
I knew I wasn't the first one!
It's close but not really an exact duplicate. I'd be happy to see the changes proposed there, but I'm proposing a different solution here (to the same problem). I think both can coexist though.
My proposal was basically a new transition mode, meaning old page is transitioned out without delay but asyncData is still respected for the new page. This could just be a catch-all default behavior you could enable for your entire application in
nuxt.conf.js
with one parameter or maybe a function that resolves per route.I do see the need for more fine-grained loading handling for specific views, but with my proposal you can still write pages as you do now, meaning you don't have to cover that additional
isLoading
state.