Co-authored-by: Daniel Roe <daniel@roe.dev> Co-authored-by: pooya parsa <pyapar@gmail.com>
4.3 KiB
Data Fetching
Nuxt provides useFetch
and useAsyncData
to handle data fetching within your application.
useAsyncData
Within your pages, components and plugins you can use useAsyncData
to get access to data that resolves asynchronously.
Usage
useAsyncData(
key: string,
fn: () => Object,
options?: { defer: boolean, server: boolean }
)
- key: a unique key to ensure that data fetching can be properly de-duplicated across requests
- fn an asynchronous function that returns a value.
- options:
- defer: whether to load the route before resolving the async function (defaults to
false
) - server: whether the fetch the data on server-side (defaults to
true
) - transform: A function that can be used to alter fn result after resolving
- pick: Only pick specified keys in this array from fn result
- defer: whether to load the route before resolving the async function (defaults to
Under the hood, defer: false
uses <Suspense>
to block the loading of the route before the data has been fetched. Consider using defer: true
and implementing a loading state instead for a snappier user experience.
Example
let counter = 0
export default () => {
counter++
return JSON.stringify(counter)
}
<script setup>
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>
<template>
Page visits: {{ data }}
</template>
useFetch
Within your pages, components and plugins you can use useFetch
to get universally fetch from any URL.
This composable provides a convenient wrapper around useAsyncData
and $fetch
and automatically generates a key based on url and fetch options and infers API response type.
Usage
useFetch(url: string, options?)
Available options:
key
: Provide a custom key- Options from ohmyfetch
method
: Request methodparams
: Query paramsbaseURL
: Base URL for request
- Options from
useAsyncData
defer
server
pick
transform
Example
<script setup>
const { data } = await useFetch('/api/count')
</script>
<template>
Page visits: {{ data.count }}
</template>
Best practices
The data returned by useAsyncData
will be stored inside the page payload. This means that every key returned that is not used in your component will be added to the payload.
::alert{icon=👉} We strongly recommend you only select the keys that you will use in your component. ::
Imagine that /api/mountains/everest
returns the following object:
{
"title": "Mount Everest",
"description": "Mount Everest is Earth's highest mountain above sea level, located in the Mahalangur Himal sub-range of the Himalayas. The China–Nepal border runs across its summit point",
"height": "8,848 m",
"countries": [
"China",
"Nepal"
],
"continent": "Asia",
"image": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Everest_kalapatthar.jpg/600px-Everest_kalapatthar.jpg"
}
If you plan to only use title
and description
in your component, you can select the keys by chaining the result of $fetch
or pick
option:
<script setup>
const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] })
</script>
<template>
<h1>{{ mountain.title }}</h1>
<p>{{ mountain.description }}</p>
</template>
Using async setup
If you are using async setup()
, the current component instance will be lost after the first await
. (This is a Vue 3 limitation.) If you want to use multiple async operations, such as multiple calls to useFetch
, you will need to use <script setup>
or await them together at the end of setup.
::alert{icon=👉}
Using <script setup>
is recommended, as it removes the limitation of using top-level await. Read more
::
<script>
export default defineComponent({
async setup() {
const [{ data: organization }, { data: repos }] = await Promise.all([
useFetch(`https://api.github.com/orgs/nuxt`),
useFetch(`https://api.github.com/orgs/nuxt/repos`)
])
return {
organization,
repos
}
}
})
</script>
<template>
<header>
<h1>{{ organization.login }}</h1>
<p>{{ organization.description }}</p>
</header>
</template>