---
title: "useAsyncData"
description: "useAsyncData 提供了一个 SSR 友好的组合式函数，用于访问异步解析的数据。"
canonical_url: "https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-async-data"
---
# useAsyncData

> useAsyncData 提供了一个 SSR 友好的组合式函数，用于访问异步解析的数据。

在你的页面、组件和插件中，你可以使用 useAsyncData 访问异步解析的数据。

::note
[`useAsyncData`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-async-data) 是一个组合式函数，旨在 Nuxt 上下文中直接调用（参见 [Nuxt 上下文](https://nuxt.zhcndoc.com/docs/3.x/guide/going-further/nuxt-app#the-nuxt-context)）。它会返回响应式组合式函数，并将响应添加到 Nuxt payload 中，以便在页面水合时从服务器传递到客户端，**而无需在客户端重新获取数据**。
::

## 用法

```vue [pages/index.vue]
<script setup lang="ts">
const { data, status, pending, error, refresh, clear } = await useAsyncData(
  'mountains',
  (_nuxtApp, { signal }) => $fetch('https://api.nuxtjs.dev/mountains', { signal }),
)
</script>
```

::warning{to="https://nuxt.zhcndoc.com/docs/3.x/guide/recipes/custom-usefetch#custom-usefetchuseasyncdata"}
如果你使用自定义的 `useAsyncData` 包装器，请勿在组合式函数中对其使用 await，因为这可能导致意外行为。请参阅自定义异步数据获取器的示例。
::

::note
`data`、`status`、`pending` 和 `error` 是 Vue 的 ref，使用时需要通过 `.value` 访问（比如在 `<script setup>` 中），而 `refresh`/`execute` 和 `clear` 是普通函数。
::

### 监听参数

内置的 `watch` 选项允许在检测到任何变化时自动重新执行获取函数。

```vue [pages/index.vue]
<script setup lang="ts">
const page = ref(1)
const { data: posts } = await useAsyncData(
  'posts',
  (_nuxtApp, { signal }) => $fetch('https://fakeApi.com/posts', {
    params: {
      page: page.value,
    },
    signal,
  }), {
    watch: [page],
  },
)
</script>
```

### 响应式键

你可以使用计算属性 ref、普通 ref 或 getter 函数作为键，允许动态数据获取，并在键变化时自动更新：

```vue [pages/[id\\].vue]
<script setup lang="ts">
const route = useRoute()
const userId = computed(() => `user-${route.params.id}`)

// 当路由变化且 userId 更新时，数据会自动重新获取
const { data: user } = useAsyncData(
  userId,
  () => fetchUserById(route.params.id),
)
</script>
```

### 使你的 `handler` 函数支持中止

你可以通过第二个参数中提供的 `signal` 来使你的 `handler` 函数可中止。当请求不再需要（例如用户离开页面时）时，这非常有用。`$fetch` 原生支持中止信号。

```ts
const { data, error } = await useAsyncData(
  'users',
  (_nuxtApp, { signal }) => $fetch('/api/users', { signal }),
)

refresh() // 实际会取消 $fetch 请求（如果 dedupe 设置为 cancel）
refresh() // 实际会取消 $fetch 请求（如果 dedupe 设置为 cancel）
refresh()

clear() // 会取消最新的待处理 handler
```

你也可以手动传入 `AbortSignal` 到 `refresh`/`execute` 函数中，以取消单独的请求。

```ts
const { refresh } = await useAsyncData(
  'users',
  (_nuxtApp, { signal }) => $fetch('/api/users', { signal }),
)
let abortController: AbortController | undefined

function handleUserAction () {
  abortController = new AbortController()
  refresh({ signal: abortController.signal })
}

function handleCancel () {
  abortController?.abort() // 终止正在进行的刷新请求
}
```

如果你的 `handler` 函数不支持中止信号，你可以利用提供的 `signal` 实现自己的中止逻辑。

```ts
const { data, error } = await useAsyncData(
  'users',
  (_nuxtApp, { signal }) => {
    return new Promise((resolve, reject) => {
      signal?.addEventListener('abort', () => {
        reject(new Error('请求已中止'))
      })
      return Promise.resolve(callback.call(this, yourHandler)).then(resolve, reject)
    })
  },
)
```

以下情况下，handler 的 signal 会被中止：

- 使用 `dedupe: 'cancel'` 发起新请求
- 调用 `clear` 函数时
- 超过 `options.timeout` 时间时

::warning
[`useAsyncData`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-async-data) 是由编译器转换的保留函数名，因此你不应将自己的函数命名为 [`useAsyncData`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-async-data)。
::

::read-more{to="https://nuxt.zhcndoc.com/docs/3.x/getting-started/data-fetching#useasyncdata"}
::

## 参数

- `key`：唯一键，确保在请求间正确去重数据获取。如果不提供，系统会为 `useAsyncData` 实例生成基于文件名和行号的唯一键。
- `handler`：异步函数，必须返回真值（例如，不应返回 `undefined` 或 `null`），否则客户端可能会重复请求数据。

::warning
`handler` 函数应当**没有副作用**，以确保 SSR 和 CSR 水合期间的行为可预测。如果你需要触发副作用，请使用 [`callOnce`](https://nuxt.zhcndoc.com/docs/3.x/api/utils/call-once) 工具函数。
::

- `options`:
  - `server`: 是否在服务器端获取数据（默认为 `true`）
  - `lazy`: 是否在加载路由后再解析 async 函数，而不是阻塞客户端导航（默认为 `false`）
  - `immediate`: 当设置为 `false` 时，将阻止请求立即触发。（默认为 `true`）
  - `default`: 一个工厂函数，用于在 async 函数解析之前设置 `data` 的默认值——对于 `lazy: true` 或 `immediate: false` 选项非常有用
  - `transform`: 一个函数，用于在解析 `handler` 函数结果后对其进行转换
  - `getCachedData`: 提供一个函数，用于返回缓存的数据。若返回 `undefined`，将触发一次获取请求。默认实现如下：
    ```ts
    const getDefaultCachedData = (key, nuxtApp, ctx) => nuxtApp.isHydrating
      ? nuxtApp.payload.data[key]
      : nuxtApp.static.data[key]
    ```

    该默认实现仅在 `nuxt.config` 启用 `experimental.payloadExtraction` 时才会缓存数据。
  - `pick`：仅从 `handler` 函数结果中提取该数组指定的键
  - `watch`：监听响应式源以自动刷新
  - `deep`：使用深层 ref 包装数据（默认值为 `true`）。如果数据无需深度响应，可设为 `false`，以提升性能。
  - `dedupe`：避免在同一时间内针对相同键发起多次请求（默认为 `cancel`），可选值：
    - `cancel` - 发起新请求时取消现有请求
    - `defer` - 如果有挂起请求，则不发起新请求
  - `timeout`：超时时间，单位毫秒（默认为 `undefined`，表示无超时）

::note
底层实现上，`lazy: false` 会利用 `<Suspense>` 阻塞路由加载，直到数据获取完成。建议使用 `lazy: true` 并实现加载状态，以获得更流畅的用户体验。
::

::read-more{to="https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-lazy-async-data"}
你可以使用 `useLazyAsyncData`，以获得与 `useAsyncData` 搭配 `lazy: true` 相同的行为。
::

::video-accordion{title="观看 Alexander Lichter 关于使用 getCachedData 进行客户端缓存的视频" videoId="aQPR0xn-MMk"}
::

### 共享状态与选项一致性

当多次调用 `useAsyncData` 使用相同键时，它们会共享同一个 `data`、`error`、`status` 和 `pending` ref。这确保了跨组件的数据一致性，但要求使用的选项也保持一致。

以下选项必须在同一键的所有调用中保持一致：

- `handler` 函数
- `deep` 选项
- `transform` 函数
- `pick` 数组
- `getCachedData` 函数
- `default` 值

以下选项可以不同且不会触发警告：

- `server`
- `lazy`
- `immediate`
- `dedupe`
- `watch`

```ts
// ❌ 这样会触发开发环境警告
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: false })
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { deep: true })

// ✅ 这样是允许的
const { data: users1 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: true })
const { data: users2 } = useAsyncData('users', (_nuxtApp, { signal }) => $fetch('/api/users', { signal }), { immediate: false })
```

::tip
使用 `useAsyncData` 创建的带键状态，可以通过 [`useNuxtData`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-nuxt-data) 在 Nuxt 应用中获取。
::

## 返回值

- `data`：传入异步函数的结果。
- `refresh`/`execute`：用于刷新 `handler` 函数返回数据的函数。
- `error`：如果数据获取失败，返回错误对象。
- `status`：表示数据请求状态的字符串：
  - `idle`：请求未开始，例如：
    - 在未调用 `execute` 且设置了 `{ immediate: false }` 时
    - 在服务器端渲染 HTML 时且设置了 `{ server: false }`
  - `pending`：请求正在进行中
  - `success`：请求成功完成
  - `error`：请求失败
- `pending`：一个 `Ref<boolean>`，在请求进行时为 `true`。
- `clear`：一个可以用来将 `data` 设置为 `undefined`（如果提供了，则设置为 `options.default()` 的值）、将 `error` 设置为 `null`、将 `status` 设置为 `idle`，并将任何当前待处理的请求标记为已取消的函数。

默认情况下，Nuxt 会等待一次 `refresh` 完成后才允许再次执行。

::note
如果你没有在服务器上获取数据（例如使用 `server: false`），那么在水合完成之前**不会**获取数据。这意味着即使你在客户端对 [`useAsyncData`](https://nuxt.zhcndoc.com/docs/3.x/api/composables/use-async-data) 使用 await，`data` 在 `<script setup>` 中仍会保持为 `undefined`。
::

## 类型

```ts [Signature]
export type AsyncDataHandler<ResT> = (nuxtApp: NuxtApp, options: { signal: AbortSignal }) => Promise<ResT>

export function useAsyncData<DataT, DataE> (
  handler: AsyncDataHandler<DataT>,
  options?: AsyncDataOptions<DataT>,
): AsyncData<DataT, DataE>
export function useAsyncData<DataT, DataE> (
  key: MaybeRefOrGetter<string>,
  handler: AsyncDataHandler<DataT>,
  options?: AsyncDataOptions<DataT>,
): Promise<AsyncData<DataT, DataE>>

type AsyncDataOptions<DataT> = {
  server?: boolean
  lazy?: boolean
  immediate?: boolean
  deep?: boolean
  dedupe?: 'cancel' | 'defer'
  default?: () => DataT | Ref<DataT> | null
  transform?: (input: DataT) => DataT | Promise<DataT>
  pick?: string[]
  watch?: MultiWatchSources | false
  getCachedData?: (key: string, nuxtApp: NuxtApp, ctx: AsyncDataRequestContext) => DataT | undefined
  timeout?: number
}

type AsyncDataRequestContext = {
  /** 本次数据请求的原因 */
  cause: 'initial' | 'refresh:manual' | 'refresh:hook' | 'watch'
}

type AsyncData<DataT, ErrorT> = {
  data: Ref<DataT | null>
  refresh: (opts?: AsyncDataExecuteOptions) => Promise<void>
  execute: (opts?: AsyncDataExecuteOptions) => Promise<void>
  clear: () => void
  error: Ref<ErrorT | null>
  status: Ref<AsyncDataRequestStatus>
  pending: Ref<boolean>
}

interface AsyncDataExecuteOptions {
  dedupe?: 'cancel' | 'defer'
  timeout?: number
  signal?: AbortSignal
}

type AsyncDataRequestStatus = 'idle' | 'pending' | 'success' | 'error'
```

::read-more{to="https://nuxt.zhcndoc.com/docs/3.x/getting-started/data-fetching"}
::

---

- [源码](https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/app/composables/asyncData.ts)


## Sitemap

See the full [sitemap](https://nuxt.zhcndoc.com/sitemap.md) for all pages.
