异步数据(AsyncData)与获取(Fetch)的区别

77
什么是fetch和asyncData数据之间的确切区别?官方文档如下所述:

asyncData

您可能希望获取数据并在服务器端呈现它。 Nuxt.js添加了一个asyncData方法,使您可以在设置组件数据之前处理异步操作。

每次在加载组件之前都会调用asyncData(仅适用于页面组件)。它可以从服务器端或在导航到相应路由之前调用。此方法将上下文对象作为第一个参数接收,您可以使用它来获取一些数据并返回组件数据。


Fetch

fetch方法用于在渲染页面之前填充存储,类似于asyncData方法,但它不设置组件数据。如果设置了fetch方法,则每次在加载组件之前都会调用(仅适用于页面组件)。它可以从服务器端或在导航到相应路由之前调用。

fetch方法将上下文对象作为第一个参数接收,我们可以使用它来获取一些数据并填充存储。要使fetch方法异步,请返回一个Promise,nuxt.js会在呈现组件之前等待Promise解析。


Fetch用于填充存储数据吗? 但在asyncData中也可以通过store提交吗?我不明白为什么有两种方法。

这两种方法都在初始加载时在服务器端运行,之后当您通过应用程序导航时在客户端运行。

有人可以解释一下使用这些方法的优点吗?

感谢帮助。

5个回答

103
让我重申一下我要说的内容前提:
  • asyncData 可以设置组件级对象并访问vuex store
  • fetch 不能设置组件级对象,但可以访问vuex store
  • 在初始加载期间,asyncDatafetch 都将在服务器端触发
  • 在初始加载后,当相应的页面路由被调用时,asyncDatafetch 将被触发

1) 如果你的设计是

  • 使用vuex store作为中央仓库
  • 为整个应用程序从vuex store访问数据

那么就使用fetch

2) 如果你的设计是

  • 使用vuex store作为中央仓库
  • 有选项设置组件级对象
  • 在特定路由中获取的数据仅由单个组件使用
  • 需要灵活性以获得vuex store或设置组件级对象的权限

那么就使用asyncData

有人能解释一下使用这些方法的优势吗?

我认为使用asyncDatafetch没有任何缺点

选择asyncDatafetch完全取决于你的架构

NuxtJS >= 2.12 更新

使用新版 NuxtJS (>= 2.12),原回答提到的几个点已不再适用。官方 RFC 公告here

在 NuxtJS 官方博客的post中,可以找到有关新行为和 asyncData 和新 fetch 之间差异的很好的解释。

至于选择哪个,我认为原回答仍然适用:

我没有看到使用 asyncDatafetch 有任何缺点

选择 asyncDatafetch 完全取决于你的架构


2
点赞!我能手动调用fetch吗?我有一个通用模式的nuxt应用程序,在其中一个页面上,我必须分页一个表格从服务器获取数据而不更改页面,如果我点击下一页按钮,我应该手动调用fetch还是怎么做? - PirateApp
2
@PirateApp 我的实际经验是,你不能手动执行“fetch”,因为“fetch”的行为受nuxtjs控制。如果你需要在页面加载后触发任何事件(用于数据获取),最好编写一个自定义方法来进行数据获取,并将“下一页按钮”绑定到它上面。 - divine
不使用它们,改用创建或挂载的钩子怎么样? - Primoz Rome
1
@PrimozRome created & mounted 钩子函数总是在客户端运行。对于特定路由的第一次请求,asyncData & fetch 将在服务器端运行。因此,使用 asyncData & fetch,您有机会在客户端加载数据,而无需在客户端进行页面加载后的任何 ajax 请求,就像您为 created & mounted 钩子函数所做的那样。 - divine
@PrimozRome 是的,正确的,在 spa 中,无论是 asyncData 还是 fetch 中的任何内容都会首先被调用,然后才会调用 created 钩子函数,最后才会调用 mounted 钩子函数。因此,在组件被创建之前,asyncDatafetch 就已经被调用了。 - divine
显示剩余7条评论

24

简而言之 - 使用 asyncData 用于在呈现页面之前必须加载的内容,使用 fetch 处理其他所有内容。

主要区别:

可用性

  • asyncData 仅在页面组件中可用
  • fetch 可用于任何组件(包括页面组件)

加载

  • asyncData 阻塞页面转换直到解析。这意味着返回的数据属性保证在组件上可用。但这也意味着用户可能需要等待更长时间才能看到内容。
  • fetch 公开一个 $fetchState.pending 属性,如何处理取决于您

错误处理

  • 如果在 asyncData 中出现错误,则页面不会呈现
  • fetch 公开一个 $fetchState.error 属性,如何处理取决于您

2
话虽如此,在 SSG 站点中,我们“应该”使用 asyncData 来检索页面上不会在导航期间更改的数据,并在 head 方法中设置动态元标记(如果使用 fetch(),则 head() 可能无法及时接收数据)。当我们想要更多地控制接收到的数据时,例如如果有一个按钮来触发 fetch() 并同时显示带有 $fetchState.pending 的占位符时,我们应该使用 fetch()。我想得对吗? - sintj
@StefanoFranceschetto 有道理。 - Marian Klühspies
1
“加载”部分真的为我澄清了很多事情。 - Shawn Lauzon

8

我想提出一个观点,我没有看到上面(至少不清楚)提到的内容。 asyncData会自动将数据合并到页面的data()对象中,但fetch不会。使用fetch时,你需要根据需求处理数据。


7

第一部分

asyncDatafetch具有不同的本质特点,因此在使用asyncData时有一个重要的优势 - Nuxt在导航到下一页之前等待 asyncData 钩子完成。

引用https://nuxtjs.org/docs/2.x/features/data-fetching#async-data:

与fetch不同,并行调用每个页面组件的asyncData方法。 在路由转换期间解析返回的 promise,这表示客户端路由转换期间无需“加载占位符”(虽然可以使用加载条将加载状态指示给用户)。 Nuxt将等待执行完所有的asyncData钩子后再导航到下一页,如果发生错误则显示错误页。

实际上意味着什么?

假设您有以下布局结构:

  • Header
  • Content
  • Footer

使用fetch时,当您打开新页面时,您可能会看到几秒钟只显示 Header 和 Footer(因为正在下载 Content 的数据)。 使用asyncData避免了这个问题,您将能够看到包含Header+Content+Footer的新页面(但该方法的缺点是需要等待几秒钟下载 Content 数据)。

第二部分

我看到网上有很多不同的地方说,如果要将东西存储在vuex中,就需要使用fetch - 这是不正确的。

下面的代码(来自我的项目)中包含了实现asyncDatafetch双重功能的代码,均可将数据存储到vuex中。

<script>
import { mapActions, mapMutations, mapState } from 'vuex'

export default {
  name: 'PagesBlog',

  async asyncData ({ store }) {
    if (!store.state.global.blogAuthors.length) {
      store.commit('global/blogAuthorsSet', await blogAuthorsDownload())
    }

    await store.dispatch('global/blogsDownloadAndSet')
  },

  async fetch () {
    if (!this.blogAuthors.length) {
      this.blogAuthorsSet(await blogAuthorsDownload())
    }

    await this.blogsDownloadAndSet()
  },

  computed: {
    ...mapState('global', [
      'blogAuthors'
    ])
  },

  methods: {
    ...mapActions('global', [
      'blogsDownloadAndSet'
    ]),

    ...mapMutations('global', [
      'blogAuthorsSet'
    ])
  }
</script>

概要

  1. 如果您有一些重要的数据(无论是对用户可见还是不可见,但需要进行某些隐藏计算)- 请使用asyncData

  2. 如果您想查看包含所有信息的页面(例如具有标题+内容+页脚)- 请使用asyncData

  3. 如果您有一些稍后可以加载的数据- 请使用fetch


Fetch钩子和Nuxt生命周期


5

I. fetch和asyncData在服务器端进行处理。

II. 可以看到使用它们的方式有所不同:

a) fetch: 更改存储数据

<script>
export default {
  async fetch ({ store, params }) {
    await store.dispatch('GET_STARS');
  }
}
</script>
b) asyncData: 更改上下文(组件数据)
<script>
export default {
  asyncData (context) {
    return { project: 'nuxt' }
  }
}
</script>

这个例子是不正确的。虽然 asyncData 确实可以改变本地/组件数据,但你也可以使用它来保存数据到 store 中。只需在你的例子中将 "fetch" 替换为 "asyncData" 即可。 - TitanFighter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接