Data Fetching Basics

Nuxt offers a set of powerful built-in tools for handling data fetching. This article examines the different methods Nuxt provides us for data fetching.

Michael Thiessen
Nuxt 3

Mastering Nuxt 3 course is here!

Get notified when we release new tutorials, lessons, and other expert Nuxt content.

Click here to view the Nuxt 3 course

Nuxt offers a set of powerful built-in tools for handling data fetching.

It provides composable functions that make it easy to fetch data and automatically handle server-side rendering, client-side hydration, and error handling. This enables you to write clean and efficient code, ensuring an optimal user experience.

In this article we’ll examine the different methods Nuxt gives us for data fetching:

  • useAsyncData
  • useFetch
  • useLazyFetch
  • useLazyAsyncData

useAsyncData

The useAsyncData composable is a powerful composable provided by Nuxt that allows you to fetch data asynchronously in your components.

This is particularly useful when you need to fetch data from an API or perform other asynchronous tasks before rendering your component.

Here's an example of how you might use useAsyncData in a music production app to fetch a list of instruments:

<template>
  <div>
    <h1>Available Instruments</h1>
    <ul v-if="!pending && !error">
      <li v-for="instrument in instruments" :key="instrument.id">
        {{ instrument.name }}
      </li>
    </ul>
    <p v-if="pending">Loading...</p>
    <p v-if="error">Error: {{ error.message }}</p>
  </div>
</template>

const { data: instruments, pending, error } = useAsyncData(
  'instruments',
  () => fetch('<https://api.example.com/instruments>')
)

In this example, we're using useAsyncData to fetch the list of instruments and assign the result to a reactive instruments variable.

We also have access to pending and error properties, which can be used to display loading and error states in our template.

You can check out the documentation for more information.

useFetch

This is another composable provided by Nuxt that simplifies data fetching in your components.

It's a wrapper around useAsyncData and provides some additional features, such as automatic key generation based on the URL and fetch options.

Here's an example of how you might use useFetch in a music production app to fetch a list of tracks for a specific project:

<template>
  <div>
    <h1>Project Tracks</h1>
    <ul v-if="!pending && !error">
      <li v-for="track in tracks" :key="track.id">
        {{ track.name }}
      </li>
    </ul>
    <p v-if="pending">Loading...</p>
    <p v-if="error">Error: {{ error.message }}</p>
  </div>
</template>

const projectId = 1
const { data: tracks, pending, error } = useFetch(
  `https://api.example.com/projects/${projectId}/tracks`
)

In the example above, we're checking if pending is true and displaying a loading message if so. Additionally, we're checking if there's an error and displaying the error message if one occurs.

To ensure your component updates when the project ID changes, you can pass in the projectId as a ref instead:

const projectId = ref(1)
const { data: tracks, pending, error } = useFetch(
  () => `https://api.example.com/projects/${projectId.value}/tracks`
)

This way, if the projectId value changes, the URL will update accordingly and the data will be fetched again.

If you want, you can check out the documentation for more information.

The key Parameter

The key parameter is an optional argument you can provide to the useAsyncData and useFetch composables to help Vue and Nuxt keep track of the data dependency between rendering on the server and the client.

Internally, the key parameter is used to create a unique identifier for the fetched data. This helps optimize the performance of your application by reducing unnecessary data fetching on the client if the data has already been fetched on the server.

Imagine you're building a music production app where users can select a project and view the associated tracks. You can use the key parameter to ensure that the tracks are updated whenever the selected project changes:

<template>
  <div>
    <select v-model="selectedProject">
      <option v-for="project in projects" :value="project.id" :key="project.id">
        {{ project.name }}
      </option>
    </select>

    <div v-if="pending">Loading tracks...</div>
    <div v-else-if="error">{{ error.message }}</div>
    <div v-else>
      <ul>
        <li v-for="track in tracks" :key="track.id">{{ track.name }}</li>
      </ul>
    </div>
  </div>
</template>

const selectedProject = ref(1)
const projects = [
  { id: 1, name: 'Project A' },
  { id: 2, name: 'Project B' },
  { id: 3, name: 'Project C' },
]

const { data: tracks, pending, error } = useAsyncData(
  'tracks',
  () => fetch(`https://api.example.com/projects/${selectedProject.value}/tracks`)
)

Here, the key parameter is tracks.

When the data is fetched on the server and passed along with the client bundle, the client knows it doesn’t need to re-fetch that data since it’s already been fetched.

If you don’t provide a key, Nuxt will automatically create one for you based on the line and file of where it’s used.

Conclusion

We’ve only covered a bit of useFetch and useAsyncData, and there’s so much more to explore!

Nuxt 3 comes with these really great tools that making data fetching so much easier on us as devs.

Michael Thiessen
Michael is a passionate full time Vue.js and Nuxt.js educator. His weekly newsletter is sent to over 11,000 Vue developers, and he has written over a hundred articles for his blog and VueSchool.

Follow MasteringNuxt on