Nuxt/docs/content/3.docs/1.usage/1.data-fetching.md

147 lines
4.2 KiB
Markdown
Raw Normal View History

# Data Fetching
2021-10-11 22:36:50 +00:00
Nuxt provides `useFetch` and `useAsyncData` to handle data fetching within your application.
## `useAsyncData`
2021-10-11 22:36:50 +00:00
Within your pages, components and plugins you can use `useAsyncData` to get access to data that resolves asynchronously.
### Usage
```js
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
2021-10-11 21:49:54 +00:00
* **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`)
2021-10-11 22:36:50 +00:00
- _transform_: A function that can be used to alter fn result after resolving
- _pick_: Only pick specified keys in this array from fn result
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
2021-10-12 10:21:00 +00:00
```js [server/api/count.ts]
2021-10-11 22:36:50 +00:00
let counter = 0
2021-10-12 10:21:00 +00:00
export default () => {
counter++
return JSON.stringify(counter)
}
2021-10-11 22:36:50 +00:00
```
```vue [app.vue]
<script setup>
2021-10-12 10:21:00 +00:00
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>
<template>
2021-10-12 10:21:00 +00:00
Page visits: {{ data }}
</template>
```
2021-10-11 22:36:50 +00:00
## `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:
```ts
useFetch(url: string, options?)
```
Available options:
- `key`: Provide a custom key
- Options from [ohmyfetch](https://github.com/unjs/ohmyfetch)
- `method`: Request method
- `params`: Query params
- `baseURL`: Base URL for request
- Options from `useAsyncData`
2021-10-11 22:36:50 +00:00
- `defer`
- `server`
- `pick`
- `transform`
### Example
```vue [app.vue]
2021-10-11 22:36:50 +00:00
<script setup>
const { data } = await useFetch('/api/count')
</script>
<template>
Page visits: {{ data.count }}
</template>
```
### Best practices
2021-10-27 11:47:13 +00:00
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:
```json
{
"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 ChinaNepal 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"
}
```
2021-10-11 22:36:50 +00:00
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:
```vue
<script setup>
2021-10-11 22:36:50 +00:00
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](https://v3.vuejs.org/api/sfc-script-setup.html#top-level-await)
::
```vue
<script>
export default defineComponent({
async setup() {
const [{ data: organization }, { data: repos }] = await Promise.all([
useFetch(`https://api.github.com/orgs/nuxtjs`),
useFetch(`https://api.github.com/orgs/nuxtjs/repos`)
])
return {
organization,
repos
}
}
})
<template>
<h1>{{ mountain.title }}</h1>
<p>{{ mountain.description }}</p>
</template>
```