Academind Logo
Pages & Data

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?

Created by Maximilian Schwarzmüller
#

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.id
this.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).