Nuxt-Notes icon indicating copy to clipboard operation
Nuxt-Notes copied to clipboard

Nuxt 3 笔记:数据获取

Open cssmagic opened this issue 1 year ago • 0 comments

方法

在 setup 阶段和生命周期钩子内可以使用以下方法:

  • useFetch
  • useLazyFetch
  • useAsyncData
  • useLazyAsyncData

useFetch() 可以认为是对 useAsyncData() + $fetch() 的简化包装。

$fetch() 方法就是一个简单的请求方法,没有其它逻辑。通常在 useAsyncData() 内部使用,或者也可以在客户端使用。

Lazy

在上述四个方法中,带 Lazy 字样的方法是普通方法的语法糖,包了一个 lazy: true 的选项进去。

<template>
  <div>
    {{ pending ? 'Loading' : count }}
  </div>
</template>
// <script setup>
const { pending, data: count } = useLazyAsyncData('count', () => $fetch('/api/count'))
watch(count, (newCount) => {
	// ...
})

在上面的例子中,await useLazyAsyncData() 得到的返回值就像是一个 Promise(但并不是,只是理念类似)。通过返回值的 pending 可以判断其状态——由于在服务端并不会发出请求,因此 pendingtrue,且 data 为 null。

虽然 data 并没有拿到真正的值,但我们可以 watch 它,等待它获取真正的值。

API

useAsyncData()/useFetch()

这两个 API 如果没有在服务端获取数据(设置选项 server: false),则只会在水合之后获取数据。这意味着,即使你在客户端 await useAsyncData()/useFetch(),在 <script setup>data 会保持为 null。(待确认)

问题:lazy 选项和 server 选项有什么区别?

  • server 选项只影响着陆阶段的请求。server: false 强制请求在浏览器端(水后之后)发出。但 server: true 并不能保证请求在服务器端发出,因为在 SPA 阶段,请求总是在浏览器端发出。
  • lazy 选项只影响 SPA 阶段的导航效果。lazy: false 强制页面在请求完成之前不更新,也就是说,页面在请求期间是卡在那里的。而在 lazy: true 的状态下,data 会经历一个从 null 到拿到真实数据的变化过程。(lazy: true 并不会导致着陆页面的请求在浏览器端发出——着陆阶段默认都是在服务器端发请求,除非有 server: false 这个选项。)

useNuxtData()

可以随时获取 4 个请求方法缓存的数据。

// 请求接口,获取数据,产生缓存
const { data } = await useFetch('/api/posts', { key: 'posts' })
// 从缓存中取数据
const { data: posts } = useNuxtData('posts')

$fetch()

是 Nuxt 3 推荐的发起 HTTP 请求的方法,用于替代 Nuxt 2 时代的 @nuxt/http 和 @nuxtjs/axios。

在 SSR 期间,如果用 $fetch() 去请求一个内部 API 路由,则会直接调用相关的函数,省去发起接口调用的消耗。

刷新

refresh()

useFetch() 的返回结果中有一个 refresh() 方法。当请求参数有变化时(比如翻页就是一个典型场景,page 参数会变化),就可以调用这个 refresh() 方法来获取新数据。所以它的作用并不是重新请求一次老数据,而是发起一个查询条件有变化的新请求。

这些变化的参数通常是响应式的,所以 refresh() 方法不接收这些变化的参数。

我们不需要关心 refresh() 的返回值,这说明上述所有 4 个请求方法的返回的 data 是响应式的。

refresh() 可接收一个 { dedupe: true } 参数,它表示如果相同请求已经发过,则忽略。

refreshNuxtData()

这个工具方法可以清除上述 4 个请求方法的缓存,并立即触发一次刷新。

同构

传递客户端 Cookie

在 SSR 阶段的请求是由服务器发出的,因此不会携带客户端的 Cookie 等请求头。我们可以用 useRequestHeaders() 来转发客户端请求头。

const headers = useRequestHeaders(['cookie'])
const { data } = await useFetch('/api/me', { headers })

可以看到这里指定了一个白名单(['cookie']),因为有些请求头是不应该转发的,我们只应该转发那些真正需要的。

传递 Cookie 到客户端

SSR 阶段发出的请求可能会收到写 cookie 的响应,此时需要把 cookie 写到客户端,整个链路才是完整的。

我们需要手工完成这个操作,示意代码参见这里: https://nuxt.com/docs/getting-started/data-fetching#example-pass-cookies-from-server-side-api-calls-on-ssr-response

最佳实践

请求方法拿到的数据会全量写入页面中(payload 由后端传递给前端),增加页面体积,因此我们需要把不需要的字段剔除掉。可以用 { pick: ['key1', 'key2'] } 参数来挑选需要保留的字段。


相关链接:

  • https://nuxt.com/docs/getting-started/data-fetching
  • https://nuxt.com/docs/api/composables/use-async-data
  • https://nuxt.com/docs/api/composables/use-fetch
  • https://nuxt.com/docs/api/composables/use-lazy-async-data
  • https://nuxt.com/docs/api/composables/use-lazy-fetch

cssmagic avatar Mar 17 '24 12:03 cssmagic