Pages & Data
In Nuxt.js apps, you use 'Pages' to define which component should get rendered for which route (URL). How do you get your data into these pages though?
What are Pages?
Okay, just in case you missed it - I got an article where I explain what "Pages" in Nuxt.js apps are.
You also should check out the official docs on that topic to find out how Nuxt.js uses "Pages" to infer a route config and get content onto the screen.
Working with Data in Pages
As you learned in the above mentioned resources, pages are also just Vue components - single component files ending with .vue
to be precise.
As such, you got access to all the default Vue component features and properties. You can add computed
properties, methods
, lifecycle hooks like created
or mounted
or set up watchers via the watch
property. Pages are just normal Vue components when it comes to that.
But they're actually a bit more than that. Nuxt.js adds some additional properties you can set. It'll check/ execute them during the server-side rendering process for the most part.
One key property you can add in a page component is the asyncData
property. You can only add it to components stored in the pages
folder, not to layouts
or components
(well, you actually can add it there, too, but it'll have no effect).
So what does asyncData
do then?
It's comparable to the normal data
property you can add to a Vue component.
export default {data() {return {myName: 'Max',}},}
In the above snippet, we add a myName
property to the Vue component by adding it to the object returned by the data
method. That's how you define component data which you in turn could use anywhere in your Vue component object (via this.myName
) or in the Vue component template (e.g. {{ myName }}
).
asyncData
is used in a similar way:
export default {asyncData() {return axios.get('my-url').then(res => {return { myName: res.data.myName }})},}
Well, you can probably see one important difference though. Here, the data isn't defined in a synchronous but asynchronous way (hence the name => asyncData
).
The data here is coming from a server but you could run any async operation in asyncData
. You also don't necessarily have to return a promise as we do in the above snippet. You could instead use a different syntax where you execute a callback or use async/await.
The key idea is: The data has to be loaded and that'll take some time. Nuxt.js will wait for the data to arrive before it continues with the component creation + template rendering.
And that's a crucial feature! It's very important for efficient server-side rendering and SEO as this approach makes sure, that search engine crawlers see what your users see. By waiting for async data to be loaded before the component is created, you can render the template with the final data. No need to show a spinner or something comparable - you just render the template with the data you would otherwise have to wait for on the client.
Therefore, asyncData
is your friend when working with asynchronous data that's required to show meaningful content on the screen.
Make sure to explore the entire docs on that topic.
Getting Information about the "context"
asyncData
is a very important property you can add to your Nuxt.js components. It has one "disadvantage" though: Due to its nature - where it gets executed before the component is created - you can't access the Vue component via this
inside asyncData
.
The following snippets would throw an error:
this.$route.params.idthis.someOtherProperty
Especially the part regarding $route
(or also regarding $store
) could be problematic though. You might want to get information about the route (and its dynamic params) the user visited. You might need to access information from your Vuex store.
Good news! You can still get access to these things!
Nuxt.js provides an argument to asyncData
which encapsulates a lot of utility properties and methods - including access to the loaded route. This argument is called context.
asyncData(context) {console.log(context.params.id)}
Often, you also see examples where only some properties are pulled out of the context
object via destructuring:
asyncData({params}) {console.log(params.id)}
With the help of context
, you can again get all the information you need - make sure to read the official docs on context to learn about all the information and utility methods you can access through it.
Vuex and Asynchronous Data
We had a look at how you may load data asynchronously before rendering a component template. This is obviously helpful but if you're using a Vuex store in your Nuxt.js app, chances are that you also want to load some data in the store on the server.
You can do that, too.
You could dispatch an action to the store from within asyncData
once the data is there. You could also use the fetch method Nuxt.js provides you with. It's basically the same as asyncData
but meant for purposes different from setting the component data.
But the easiest way to pre-populate the Vuex store with asynchronously loaded data probably is to use nuxtServerInit
.
It's a special action which you add to your Vuex store which will be dispatched automatically by Nuxt.js on the server-side. It can be used to load some data asynchronously and Nuxt.js will wait for this action to finish before it finishes the rendering of your page.
nuxtServerInit
is simply added to your other Vuex actions - it could look like this:
actions: {nuxtServerInit ({ commit }, { req }) {if (req.session.user) {commit('user', req.session.user)}}}
This example is actually taken from the official docs which I again strongly recommend checking out.
In the above snippet, destructuring is used to extract some properties from the two arguments nuxtServerInit
automatically receives: The store and the context (which you already know from asyncData
).