您正在浏览 Nuxt 2 文档。前往 Nuxt 3 文档, 或了解更多关于 Nuxt 2 长期支持

数据获取

Nuxt 中有两种从 API 获取数据的方式,可以使用 fetch 方法或 asyncData 方法。


Nuxt 支持 Vue 在客户端应用中的传统数据获取模式,例如在组件的 mounted() 钩子中获取数据。但在通用应用中,需要使用 Nuxt 特有的钩子在服务端渲染期间渲染数据,从而确保页面渲染时所有必要数据都已存在。

Nuxt 提供了两个用于异步加载数据的钩子:

  • asyncData。该钩子只能在 页面 组件中使用。与 fetch 不同,它在客户端渲染期间不显示加载占位符,而是阻塞路由导航直到钩子解析完成,失败时显示错误页面。
  • fetch(Nuxt 2.12 及以上)。可以放置在任何组件中,提供渲染(客户端渲染期间的)加载状态和错误的快捷方式。

这些钩子可以与你选择的 任何数据获取库 配合使用。推荐使用 @nuxt/http @nuxt/axios 向 HTTP API 发送请求。更多关于这些库的信息(例如设置认证请求头)可以在各自的文档中找到。

如果在 mixin 中定义了 fetchasyncData,同时在组件或页面中也定义了,mixin 函数将被覆盖而不会被调用。

fetch 钩子

在 Nuxt 2.12 之前,存在一个仅适用于 页面 组件且无法访问组件实例的 fetch 钩子。如果 fetch() 接收 context 参数,则会被视为旧版 fetch 钩子。该功能已废弃,请用 asyncData匿名中间件 (anonymous middleware) 替代。

fetch 是一个在服务端渲染时于组件实例创建后调用、在客户端于导航时调用的钩子。fetch 钩子应返回一个 promise(显式地,或通过 async/await 隐式地),该 promise 在以下时机解析:

  • 在服务器上,初始页面渲染之前
  • 在客户端上,组件挂载之后
对于静态托管 ,fetch 钩子仅在页面生成时调用,其结果会被缓存供客户端使用。为避免缓存冲突,可能需要指定组件名称或提供唯一的 fetchKey 实现。

使用方法

数据获取 (Fetching)

在 fetch 钩子内,可以通过 this 访问组件实例。

请确保要更新的属性已在 data() 中声明。这样才能将获取到的数据赋值给这些属性。

修改 fetch 行为

fetchOnServer: BooleanFunction(默认值:true)。服务器渲染页面时调用 fetch()

fetchKey: StringFunction(默认为组件的作用域 ID 或组件名称),用于标识组件 fetch 结果的键(或生成唯一键的函数)。(Nuxt 2.15 及以上有效,详细信息见 GitHub 拉取请求 )。在对服务器渲染的页面进行水合时,该键用于将服务端 fetch() 的结果映射到客户端组件数据。详情请参阅 PR。

fetchDelay: Integer(默认值:200)。设置最小执行时间(毫秒)(用于防止快速闪烁)。

fetchOnServer 为 falsy(false 或求值为 false 的值)时,fetch 仅在客户端调用,服务器渲染组件期间 $fetchState.pending 返回 true

export default {
  data: () => ({
    posts: []
  }),
  async fetch() {
    this.posts = await this.$http.$get('https://api.nuxtjs.dev/posts')
  },
  fetchOnServer: false,
  // 多个组件可以返回相同的 `fetchKey`,Nuxt 会分别追踪它们
  fetchKey: 'site-sidebar',
  // 作为替代方案,如果需要更多控制,可以传入一个能访问组件实例的函数
  // 该函数在 `created` 中调用,不应依赖已获取的数据
  fetchKey(getCounter) {
    // getCounter 是一个可调用的方法,用于在生成唯一 fetchKey 时
    // 获取序列中的下一个数字
    return this.someOtherData + getCounter('sidebar')
  }
}

访问 fetch 状态

fetch 钩子在组件级别暴露 this.$fetchState,包含以下属性:

  • pending 是一个 Boolean,表示在 客户端 调用 fetch 时是否显示占位符
  • errornull 或 fetch 钩子抛出的 Error
  • timestamp 是最后一次 fetch 的时间戳,可用于通过 keep-alive 缓存

除了 Nuxt 调用的 fetch,还可以在组件内通过 this.$fetch() 手动调用 fetch(例如重新加载异步数据)。

components/NuxtMountains.vue
<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>
    <button @click="$fetch">Refresh</button>
  </div>
</template>

<script>
  export default {
    data() {
      return {
        mountains: []
      }
    },
    async fetch() {
      this.mountains = await fetch(
        'https://api.nuxtjs.dev/mountains'
      ).then(res => res.json())
    }
  }
</script>
在 fetch 钩子内,可以通过 this.$nuxt.context 访问 Nuxt context

监听查询字符串变化

默认情况下,查询字符串变化不会触发 fetch 钩子。要监听查询字符串变化,可以在侦听器中添加 $route.query 并调用 $fetch

export default {
  watch: {
    '$route.query': '$fetch'
  },
  async fetch() {
    // 查询字符串变化时也会被调用
  }
}

缓存

可以在 <nuxt/><nuxt-child/> 组件中使用 keep-alive 指令来保存已访问页面的 fetch 调用:

layouts/default.vue
<template>
  <nuxt keep-alive />
</template>

还可以通过向 <nuxt> 组件传递 keep-alive-props 属性来指定传给 <keep-alive>props

layouts/default.vue
<nuxt keep-alive :keep-alive-props="{ max: 10 }" />

在内存中保存 10 个页面组件。

错误处理

获取数据时发生错误,通常不会加载 Nuxt 错误页面,也不应在 fetch() 内使用 Nuxt 的 redirecterror 方法。应改为在组件内使用 $fetchState.error 处理错误。

获取数据发生错误时,通过 $fetchState.error 检查并显示错误信息。

components/MountainsList.vue
<template>
  <div>
    <p v-if="$fetchState.pending">Loading....</p>
    <p v-else-if="$fetchState.error">Error while fetching mountains</p>
    <ul v-else>
      <li v-for="(mountain, index) in mountains" :key="index">
        {{ mountain.title }}
      </li>
    </ul>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        mountains: []
      }
    },
    async fetch() {
      this.mountains = await fetch(
        'https://api.nuxtjs.dev/mountains'
      ).then(res => res.json())
    }
  }
</script>

使用 activated 钩子

Nuxt 将最后一次调用 fetch 的时间(包括 SSR)直接存储在 this.$fetchState.timestamp 中。将该属性与 activated 钩子结合使用,可以为 fetch 添加 30 秒缓存:

pages/posts/_id.vue
<template> ... </template>

<script>
  export default {
    data() {
      return {
        posts: []
      }
    },
    activated() {
      // 如果距上次 fetch 超过 30 秒,则重新调用 fetch
      if (this.$fetchState.timestamp <= Date.now() - 30000) {
        this.$fetch()
      }
    },
    async fetch() {
      this.posts = await fetch('https://api.nuxtjs.dev/posts').then(res =>
        res.json()
      )
    }
  }
</script>

如果最后一次 fetch 调用在 30 秒以内,则导航到同一页面时不会再次调用 fetch

Async Data

asyncData 仅在 pages 中可用,在该钩子内无法访问 this

asyncData 是另一个用于通用数据获取的钩子。与需要设置组件实例属性(或分发 Vuex action)来保存异步状态的 fetch 不同,asyncData 只需将返回值合并到组件数据中。以下是使用 @nuxt/http 库的示例:

pages/posts/_id.vue
<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.description }}</p>
  </div>
</template>

<script>
  export default {
    async asyncData({ params, $http }) {
      const post = await $http.$get(`https://api.nuxtjs.dev/posts/${params.id}`)
      return { post }
    }
  }
</script>

fetch 不同,asyncData 钩子返回的 promise 在 路由切换期间 解析,这意味着客户端切换时不会显示"加载占位符"(但可以使用加载进度条 向用户展示加载状态)。Nuxt 会等待 asyncData 钩子完成后再导航到下一个页面或显示错误页面

该钩子只能用于页面级组件。与 fetch 不同,asyncData 无法访问组件实例(this),而是接收 context 作为参数。可以使用 asyncData 获取数据,Nuxt 会自动将返回的对象与组件数据进行浅合并(shallow merge)。

后续示例将使用推荐的 @nuxt/http 从 API 获取数据。

组件的异步数据?

由于组件没有 asyncData 方法,无法在组件内直接从服务器获取异步数据。要绕过此限制,有三种基本选项:

  1. 使用 Nuxt 2.12 及以上版本启用的fetch 钩子
  2. mounted 钩子中调用 API 并在加载时设置数据属性。缺点:服务端渲染中不起作用。
  3. 在页面组件的 asyncData 方法中调用 API,并将数据作为属性传递给子组件。服务器渲染正常工作。缺点:页面的 asyncData 需要加载其他组件的数据,可能导致可读性下降。

监听查询字符串变化

默认情况下,查询字符串变化不会触发 asyncData 方法。如果想改变此行为(例如构建分页组件),可以在页面组件的 watchQuery 属性中设置要监听的参数。

Edit this page on GitHub Updated at Tue, Apr 14, 2026