In order to realize those benefits of pre-rendering, you need to make certain that your server-side rendering has all of the data it needs before rendering. This is trivial for static pages, but for dynamic applications that depend on API calls, you will need to make sure all critical data is fetched before the page is rendered and sent from the server.
This is a hook that Nuxt has inserted into it's initialization process for populating VueX store data that should always be there. It is called on the server only, and is used for populating store data that should be there on every page load.
The way it works is that if your primary store index has defined nuxtServerInit as an action, it will be run prior to any middleware or other page intialization. It can be synchronous or asynchronous; if it returns a promise Nuxt will wait for that promise to resolve before continuing.
For example, we might use this to populate current user data:
Middleware lets you define custom functions that run before rendering a page or group of pages. It can be used to guard pages or layouts, for example by checking if a user is authenticated to see them, but it can also be used to fetch asynchronous data. It doesn't have direct access to the page, as that page has not rendered yet, but it can populate the store.
One benefit of middleware is it is reusable - you can apply the same middleware to multiple pages, or a whole group that share a layout. This makes it a very nice place to put data preloading that is shared across a set of pages, but not global across your application like nuxtServerInit.
The downside of using middleware is that by the time it runs, it is not yet guaranteed the page will render. Later middleware or the validate hook might still prevent the page from rendering, so if your API calls are particularly expensive you might want to save them for later in the lifecycle.
As an example of how we might use middleware, let's imagine that whenever a user is in their "account" area we want to preload a set of settings for them. This might look like:
This middleware checks to see if the settings value in the settings module of the VueX store is empty. If so, it dispatches an action to fill it, if not it simply returns true.
So long as that action returns a promise, by returning the result of the dispatch our middleware also returns a promise. Nuxt will wait for that promise to be resolved before continuing, and thus that action can populate our store before rendering.
The fetch hook is also used to initialize the VueX store before rendering, but rather than being globally applied to every page, it is page specific. It will not be called if defined on layouts or sub-page components, only within a page.
A fetch method defined on a page component will be called after all middleware has run and validation has cleared, so by the time it runs we know for certain this page will render. This makes it ideal for fetching expensive data that is necessary for page render but that you wouldn't want to do speculatively.
One quick note: Despite being defined within a page component, it is called before that component is completely initialized, so it does not have access to that component's data, computed attributes, etc. In fact, this will not refer to the component at all. Instead, the fetch method is passed the context object so you can access the store and other needed functionality.
An example of using the fetch method to fetch a specific product's info into the store:
Up until this point, all of the mechanisms we've covered have been focused on populating data into the VueX store. But sometimes you don't need (or want) the store, you just want to put data into your component's data object.
Nuxt has you covered here too, at least for within a page component, with the asyncData hook. This hook will be called prior to rendering a page, and the object it returns will be merged with the data object for your component.
For example, if for some reason we didn't want to use the VueX store in our previous example to hold product data - perhaps we want to make sure it is always 100% up to date and so refetch it every time the product page is viewed. We could implement it this way: