Nuxt3 SSR 数据请求避坑:useFetch 与 useAsyncData 怎么选

发布于2026-09-11 10:09 阅读15次 在 Nuxt3 项目里请求数据时该用 useFetch 还是 useAsyncData?两者看起来很像,用错了会导致重复请求、水合报错或首屏白屏。本文用实测对比讲清适用场景与缓存机制,并总结五条实战避坑经验,帮你少走弯路,把服务端渲染的数据请求彻底搞清楚。
# 一、一句话区分
- **useFetch**:封装了 $fetch,自动处理 URL、参数、SSR 数据传递,**最简单**,适合单一接口请求。
- **useAsyncData**:更底层,需要自己写请求函数,**更灵活**,适合同步拿多份数据、有复杂逻辑或需要自定义 key 的场景。
# 二、SSR 下为什么不能直接用 onMounted + fetch
服务端渲染时 `onMounted` 根本不会执行,客户端拿到的是**空数据**,于是出现首屏白屏、内容闪烁(水合不一致)。正确做法是用 Nuxt 提供的这两个组合函数,它们会把服务端取到的数据**序列化后传给客户端**,避免二次请求。
# 三、实战代码对比
```js
// useFetch:一行搞定,自动传参、自动水合
const { data, pending, error } = await useFetch("/api/posts", {
query: { page: 1 },
key: "posts-list" // 显式 key 便于缓存控制
})
```
```js
// useAsyncData:需要合并多个接口时更合适
const { data } = await useAsyncData("home-data", async () => {
const [user, posts] = await Promise.all([
$fetch("/api/user"),
$fetch("/api/posts")
])
return { user, posts }
})
```
# 四、五条避坑经验
1. **key 要唯一且稳定**——不写 key 时 Nuxt 会按调用位置自动生成,组件复用时可能意外共享数据;
2. **watch 参数变化**——分页、搜索这类场景加 `watch: [page]`,否则翻页不会重新请求;
3. **await 与不 await 的差别**——`await useFetch` 会阻塞渲染直到数据就绪(适合 SEO 首屏),不 await 则是客户端懒加载;
4. **别在循环里调用**——容易造成请求爆炸,应该把批量逻辑放进一个 useAsyncData 里;
5. **错误处理用 error 而非 try/catch**——这两个函数内部已捕获错误,用返回的 `error` 状态展示降级 UI。
# 五、缓存与刷新
`useFetch` 默认会缓存同 key 的结果,跨页面复用数据不再重复请求。需要强制刷新用 `refresh()`,需要立即重新请求用 `execute()`。
# 六、总结
一句话:**单接口用 useFetch,多接口或复杂逻辑用 useAsyncData**。两者都能解决 SSR 数据传递问题,选型的核心是看请求复杂度,而不是哪个看着更"高级"。