08 / 09

为什么 useFetch 不是 fetch?

理解 useFetch 如何连接服务端请求、Payload 与客户端状态。

为什么 useFetch 不是 fetch?

这一章进入 Nuxt 数据获取(Data Fetching),这也是 Nuxt 和 Vue 最大的区别之一。

讨论的核心不是 useFetch 怎么用,而是:

既然浏览器已经有 fetch(),Nuxt 为什么还要重新设计一个 useFetch()?


学习目标

理解为什么不能直接使用 fetch()useFetch() 解决了哪些问题,以及为什么它能配合 SSR 工作。


一、这个知识解决什么问题?

JavaScript 原生已经提供了 fetch('/api/user'),Vue 项目里也一直这样写。

那么 Nuxt 为什么还要重新设计 useFetch()?如果只是换了名字,那完全没有必要。所以:

useFetch 一定解决了 fetch 解决不了的问题。


二、一起推导

假设页面这样写:

const user = await fetch('/api/user')

根据前面几章我们已经知道:第一次访问页面时,服务器会执行这段代码,请求 /api/user(第一次)。

但是浏览器下载 JavaScript 后,组件还会执行一次。浏览器又执行了 fetch('/api/user')(第二次)。

同一个接口,请求了两次。

原生 fetch 最大的问题:

它不知道自己正运行在 Nuxt 的 SSR 生命周期里。


三、useFetch 做了什么?

Nuxt 在 fetch 外面包了一层,形成 useFetch(),除了请求接口,还做了四件事:

第一:支持 SSR

同一份代码,服务器和浏览器都能执行,不需要额外处理。

第二:支持 Payload

服务器请求到的数据,会被放进 Payload 一起发给浏览器。浏览器 Hydration 时直接读取,不再重复请求。

第三:自动管理状态

fetch() 需要自己管理 loadingerrordatauseFetch() 直接提供:

const { data, pending, error } = useFetch(...)

第四:自动响应路由变化

当请求参数使用了响应式路由参数时,useFetch 可以监听依赖并重新获取数据。


四、fetch 与 useFetch 对比

能力 fetch useFetch
HTTP 请求
SSR 支持 ❌ 自己处理
Payload
避免首次重复请求
pending / error
响应式 data
Nuxt 生命周期

更准确地说:

useFetch = fetch + SSR + Payload + 响应式 + 状态管理 + Nuxt 生命周期

五、脑图

fetch 与 useFetch 在 Nuxt SSR 中的数据流对比脑图

读图时不要只比较"是否能发送 HTTP 请求",而要看完整生命周期:

  1. 原生 fetch 只返回一次网络响应,不知道服务器数据应该如何交给 Hydration
  2. useFetch 在服务端请求数据后,将结果以稳定 key 写入 Nuxt Payload
  3. 客户端执行到同一个 useFetch 时,先用 key 查找 Payload,命中后直接恢复响应式状态
  4. 后续刷新、响应式参数变化等场景,才会重新执行请求

六、容易踩坑

❌ useFetch 就是 fetch

不是。增加了 SSR、Payload、Cache、响应式、生命周期,已经完全不是一个层级。

❌ useFetch 不会执行两次

实际上 Server 和 Client 都会执行,但 Client 读取的是 Payload,所以不会重复请求网络。

❌ fetch 在 Nuxt 不能用

可以用,只是无法享受 SSR、Payload、Hydration 等配套能力。


一句话记忆

fetch 只会请求数据;useFetch 管理的是整个 Nuxt 数据获取生命周期。