Vue.js Developers
Published in

Vue.js Developers

Universal data fetching in Nuxt.js

AsyncData vs Fetch vs Middlewares vs Vue Hooks

Mounted hook

Let's get this out of the way first. Fetching data during component initialization is still possible. This way the data are fetched on the client and the page load is not blocked. This is useful for nonessential data and does not affect server response time at all.

AsyncData

This is a special Nuxt lifecycle hook available only in page components. It will be triggered during server-side rendering before the component instance is created, and on the client when navigating. Navigation until the API call is fulfilled will be blocked. It has access to the Nuxt context (which also contains the store instance) but not in the component instance (this) which is the main difference with fetch hook. The return value of this function will be shallow merged with the component data.

<template>
<div>
<h1>{{ post.title }}</h1>
<p>{{ post.description }}</p>
</div>
</template>

<script>
export default {
async asyncData({ params, $http }) {
// This could also be an action dispatch
const post = await $http.$get(`/posts/${params.id}`)
return {
post
}
}
}
</script>

Legacy Fetch — (Before 2.12)

The old fetch hook worked much like asyncData does. It’s still available for backward compatibility when a context argument is used. The main difference between them is that fetch runs after component initialization which means that it has access to the component instance. The fetch hook is not blocking which means route navigation will happen and a loading state needs to be handled by the component.

New Fetch — (After 2.12)

The updated fetch hook is another way to make API calls during server-side rendering but can be placed in any component of a page.

  • error is either null or an Error thrown by the fetch hook
  • the timestamp is a timestamp of the last fetch, useful for caching with keep-alive
<template>
<p v-if="$fetchState.pending">Fetching mountains...</p>
<p v-else-if="$fetchState.error">An error occurred :(</p>
<div v-else>
<h1>Nuxt Mountains</h1>
<ul>
<li v-for="mountain of mountains">{{ mountain.title }}</li>
</ul>
</div>
</template>

<script>
export default {
data() {
return {
mountains: []
}
},
async fetch() {
// This could also be an action dispatch
this.mountains = await fetch(
'https://api.nuxtjs.dev/mountains'
).then(res => res.json())
}
}
</script>
  • fetchDelay (default: 200): Fetching delay in milliseconds

Middlewares

Middlewares are custom functions that can be run before rendering either a page or a layout. They also accept the context as a parameter which means they have access to the store and can make API calls. The only downside in using them is that multiple middlewares run in sequence and if they contain API calls they won’t be done in parallel.

import http from 'http'

export default function ({ route }) {
return http.post('http://my-stats-api.com', {
url: route.fullPath
})
}

NuxtServerInit

This is a special hook that runs during Vuex store initialization. This is the best place to fetch data that needs to be available across the whole application, like configurations, feature toggles, authentication info, etc.

Conclusion

A lot of options but in reality, it’s pretty straightforward:

Additional resources

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store