Nuxt 官方文档对数据获取的主线已经非常清楚:
$fetchuseFetchuseAsyncData
很多人学不明白,不是 API 看不懂,而是心智没立住。
先看最重要的关系:
$fetch
├── 最简单的请求函数
├── 更适合事件触发
└── 单独用在 setup 里可能双取
useFetch
├── 基于 $fetch
├── SSR 安全
├── 会把服务端数据带到客户端 payload
└── 最适合页面初始数据
useAsyncData
├── 更通用的异步包装层
├── 更细粒度控制
└── 适合复杂组合查询#1. useFetch —— 栏目开播时就要准备好的数据
<script setup lang="ts">
const { data, status, error, refresh } = await useFetch('/api/news')
</script>
<template>
<div v-if="status === 'pending'">新闻加载中...</div>
<div v-else-if="error">加载失败</div>
<ul v-else>
<li v-for="item in data" :key="item.id">
{{ item.title }}
</li>
</ul>
</template>Nuxt 官方强调:它会避免“服务端取一次、客户端水合再取一次”的双重请求问题。
#2. $fetch —— 用户点击后才发出的互动请求
<script setup lang="ts">
async function subscribeChannel() {
await $fetch('/api/subscriptions', {
method: 'POST',
body: {
channel: 'news'
}
})
}
</script>
<template>
<button @click="subscribeChannel">订阅栏目</button>
</template>适合:
- 按钮点击
- 表单提交
- 用户触发后的请求
不适合直接拿来当“首屏主数据”方案。
#3. useAsyncData —— 多路内容汇总编排
<script setup lang="ts">
const { data } = await useAsyncData('home-dashboard', async () => {
const [headline, ranking] = await Promise.all([
$fetch('/api/headline'),
$fetch('/api/ranking')
])
return { headline, ranking }
})
</script>当你需要:
- 聚合多个接口
- 自定义 key
- 自定义 transform
- 更灵活的缓存策略
就该优先想到 useAsyncData。
#4. lazy、server: false、pick 这些选项到底在干什么?
官方文档里这部分很实用,可以翻成大白话:
lazy: true:别挡住整页跳转,先过去再慢慢补数据server: false:这个数据别在服务端取,只在浏览器取pick:接口返回很多字段,但只把真要用的字段塞进 payloadtransform:在进入页面前先把结果整理好
<script setup lang="ts">
const { data: posts, status } = useFetch('/api/posts', {
lazy: true,
pick: ['title', 'slug']
})
</script>#5. 一个铁律:别把数据获取写成玄学
首屏关键数据 → useFetch / useAsyncData
用户事件触发 → $fetch
复杂聚合逻辑 → useAsyncData
非首屏、非 SEO 关键 → lazy + server:false 可考虑