数据刷新与缓存
本教程共 50 篇 · 第 25 篇 · 更新于 2026-08-08 · 约 7 分钟阅读
本节目标:掌握 refresh / execute 的局部刷新,以及 refreshNuxtData / clearNuxtData 的全局刷新与缓存清理。
25-1
数据不是取一次就永远不变。用户点了「刷新」按钮,或者表单提交成功后,你都希望页面上的列表能立刻更新。Nuxt 的取数组合式函数自带刷新能力,不用你手动再写一遍请求。
回顾一下,useFetch 和 useAsyncData 返回值里都有一个 refresh(别名 execute)。它就是对「重新跑一次取数逻辑」的封装。
25-2
最常见的用法,是绑定到一个按钮:
<script setup lang="ts">
const { data, error, refresh } = await useFetch('/api/users')
</script>
<template>
<div>
<ul>
<li v-for="u in data" :key="u.id">{{ u.name }}</li>
</ul>
<button @click="refresh()">刷新数据</button>
</div>
</template>
点一下,就会用原来那份「取数逻辑」(handler 或 URL)重新请求,data 自动变成新结果。execute 和 refresh 作用完全一样,只是语义上更适合「本来没立即执行、由我主动触发」的场景。
Note默认情况下,Nuxt 会等上一次
refresh真正完成,才允许下一次执行。也就是说刷新不会被你疯狂连点而叠成一堆并发请求,框架帮你做了去重和排队。
25-3
如果有一个响应式值(比如筛选条件、页码)变了,你就想重新取数,可以用 watch 选项:
<script setup lang="ts">
const id = ref(1)
const { data, refresh } = await useFetch('/api/users', {
// id 变化时自动重新请求
watch: [id],
})
</script>
不过要注意一个细节:watch 监听的是「响应式值变了就重跑取数逻辑」,它不会改变 URL 本身。比如你写 useFetch('/api/users/${id.value}', { watch: [id] }),URL 在调用那一刻就已经拼好了,之后 id 变了重跑,用的还是最开始那个 URL。
Warning想让 URL 跟着响应式值变,要么把动态部分放进
query(Nuxt 会自动监听 query 里的响应式值并重抓),要么把整个 URL 写成一个 getter 函数:useLazyFetch(() => '/api/users/${id.value}', { immediate: false })。
25-4
最干净的做法,是把依赖参数放进 query,Nuxt 会监听其中的响应式值并自动重抓:
<script setup lang="ts">
const id = ref(null)
const { data, status } = useLazyFetch('/api/user', {
query: {
user_id: id,
},
})
</script>
复杂一点的,可以用返回字符串的 getter 当 URL,每次依赖变化就用新地址重新取:
<script setup lang="ts">
const id = ref(null)
const { data, status } = useLazyFetch(() => `/api/users/${id.value}`, {
immediate: false,
})
</script>
25-5
useFetch 和 useAsyncData 靠「键」来避免重复取数。重点规则:
useFetch的 key 由 URL + 请求选项 + 调用位置共同决定。所以不同组件里相同 URL 的两次useFetch,key 是不同的,会各发各的请求。- 想让多个组件共享同一份数据,就显式传同一个
key:
<script setup lang="ts">
const { data } = await useFetch('/api/info', { key: 'shared-info' })
</script>
<script setup lang="ts">
// 同一个 key,复用上面那份数据,不再发请求
const { data } = await useFetch('/api/info', { key: 'shared-info' })
</script>
useAsyncData的 key 就是第一个字符串参数;只传 handler 时 key 自动生成(按文件+行号),自己封装时务必手动给 key。
Tip想按 key 直接读出已缓存的数据,用
useNuxtData(key)。它返回当前缓存的data和status,适合「我只要读、不要重新取」的场景。
25-6
局部 refresh 只刷某一个取数。如果你的操作影响到了多份数据(比如提交了一个会影响好几个列表的表单),可以用全局刷新 refreshNuxtData:
<script setup lang="ts">
async function submit () {
await $fetch('/api/report', { method: 'POST', body: form })
// 重新拉取所有(或指定 key 的)缓存数据
await refreshNuxtData()
}
</script>
它还能精准指定只刷某几个 key:
// 只刷新这两份缓存
await refreshNuxtData(['users', 'stats'])
底层逻辑是:Nuxt 找到这些 key 对应的取数函数,重新执行一遍,更新缓存和所有引用了它们的组件。
25-7
如果用户快速连续触发刷新,或者 watch 监听的值短时间变了好几次,你可能不希望每次都真去请求。useFetch / useAsyncData 有一个 dedupe 选项,控制「上一次还没完成时,新的触发怎么处理」:
dedupe: 'cancel':新的触发会取消上一次、自己抢跑(默认在immediate场景下的行为偏保守,按需设置)。dedupe: 'defer':上一次没完成就先等着,完成后再看要不要补一次。
<script setup lang="ts">
const keyword = ref('')
const { data, status } = await useFetch('/api/search', {
query: { q: keyword },
// 输入停顿期间不堆叠请求
dedupe: 'defer',
})
</script>
配合 watch + query 做「输入即搜索」时,dedupe 能有效压住请求量,避免一秒钟打出十几发请求打爆接口。
Tip如果你想要「用户停止输入 300 毫秒后才请求」那种体验,可以在
watch的回调里自己做防抖(debounce),而不是依赖dedupe。dedupe管的是「并发去重」,防抖管的是「延后触发」,两者互补。
25-8
极少数高级场景,你想在「取数前」先自己决定要不要复用旧缓存、或读取一份特殊来源的数据。这时可以用 getCachedData 选项,它让你拿到当前 key 已有的缓存,自行决定是否用、怎么用:
const { data } = await useAsyncData('stats', () => $fetch('/api/stats'), {
getCachedData: (key, nuxtApp) => {
// 返回非 undefined 就会直接复用,不再发请求
return nuxtApp.payload.data[key]
},
})
绝大多数应用用不到它。知道「有这个能力」即可,等真遇到「标准缓存不够灵活」的诉求再回头翻文档。
25-9
有些场景你想「主动把缓存清空」,让下次进入页面时重新取数。比如用户登出后,个人数据缓存应当作废。clearNuxtData(key) 就是干这个的:
function logout () {
clearNuxtData('profile')
// 不传 key 则清空全部缓存
}
对应地,状态也有 clearNuxtState(见第 27 章)。
25-10
缓存的是「取到的数据」,而这些数据会通过 payload 从服务器传到浏览器。用 pick 只挑需要的字段,或用 transform 做映射,都能让 payload 变小:
<script setup lang="ts">
const { data: mountain } = await useFetch('/api/mountains/everest', {
pick: ['title', 'description'],
})
</script>
Note
pick/transform不会减少「服务器实际去取」的数据量,但会减少「跟着 HTML 传到浏览器」的体积,对首屏传输是实打实的优化。
25-11
refresh、refreshNuxtData、clearNuxtData、watch、query 等机制在 Nuxt 3 与 Nuxt 4 中行为一致,无破坏性差异。Nuxt 4 仅目录约定不同。
25-12
刷新分两层:局部用返回值里的 refresh / execute,全局用 refreshNuxtData。缓存的核心永远是这个 key——相同 key 共享数据、避免重复请求;想精准控制就用显式 key。配合 clearNuxtData 和 watch/query,你就能让数据既「不重复取」又「该新就新」。下一章进入状态管理,先看官方的 Pinia。
25-7 缓存策略的实际应用
在实际项目中,合理的缓存策略能显著提升用户体验并降低服务器压力。Nuxt 的 useFetch 和 useAsyncData 都支持 getCachedData 选项,让你自定义缓存逻辑。
对于变化不频繁的数据(如网站配置、分类列表),可以设置较长的缓存时间,减少重复请求。对于实时性要求高的数据(如库存、价格),则应该每次页面加载都重新获取。关键是区分数据的”新鲜度需求”,按需制定策略。
SWR(Stale-While-Revalidate)是一种常用的缓存策略:先展示缓存的旧数据,同时在后台发起新请求,拿到新数据后自动更新页面。这种策略让用户几乎感受不到等待,同时保证数据最终是最新的。Nuxt 的缓存机制天然支持这种模式。
25-8 缓存失效的处理策略
缓存虽好,但缓存失效是一个绕不开的话题。当数据在源端更新了,缓存里的旧数据什么时候该被淘汰?Nuxt 提供了几种机制来处理这个问题。
最直接的方式是设置缓存的最大存活时间(TTL)。超过这个时间,下次访问时会自动重新获取数据。对于变化规律可预测的数据(如每小时更新一次的统计数据),TTL 策略简单有效。
另一种方式是主动失效。当数据发生更新时(比如用户提交了表单修改了数据),在提交成功后手动清除对应的缓存。Nuxt 的 useFetch 返回的 clear 方法可以做到这一点。两种策略可以结合使用:TTL 作为兜底保障,主动失效保证关键操作的即时性。