Next.js 13 从 Sanity v3 获取数据时存在 stale(脏缓存数据)问题求助
兄弟我太懂你这种缓存不更新的抓狂感了!我之前用Next13搭Sanity博客的时候也踩过几乎一模一样的坑,咱们一步步来给你排查解决:
首先搞清楚核心问题:Next13的静态渲染缓存
你的Home页面是用App Router的服务器组件写的,Next13默认会把这种async服务器组件预渲染成静态页面——也就是说,第一次构建后的数据就被缓存死了,哪怕Sanity里的数据改了,前端还是会用旧的缓存内容,硬刷新都没用!
解决方案1:强制页面动态渲染
直接在你的page.tsx顶部加一行配置,告诉Next.js每次请求都要重新拉取数据,别用静态缓存:
// 放在page.tsx的最顶部,import语句之后 export const dynamic = 'force-dynamic'; // 或者用另一种写法,效果一样: // export const revalidate = 0;
这样每次用户访问页面,都会重新执行client.fetch去Sanity拿最新数据,不会再用之前的静态缓存。
解决方案2:修改Sanity查询,过滤草稿文档
你说在Sanity里撤下了一篇文档,其实撤下的文档会变成草稿状态(ID以drafts.开头),而你的原始查询*[_type == "post"]会把草稿和已发布的文档都拉回来(如果你的client带了有权限读草稿的token),所以得在查询里过滤掉草稿:
*[_type == "post" && !(_id in path("drafts.**"))] { ..., description, author->, categories[]-> } | order(_createdAt desc)
加个!(_id in path("drafts.**"))就能确保只拉取已发布的正式内容,撤下的草稿就不会再出现在结果里了。
解决方案3:检查Sanity Client的配置细节
看看你的client配置里这几个点:
- apiVersion:必须是
YYYY-MM-DD的日期格式,建议用最近的日期(比如2024-05-20),旧的api版本可能会有兼容性问题,导致数据同步异常 - token:你把token放在
NEXT_PUBLIC_前缀下是会暴露给前端的,如果只是拉取公开的已发布内容,其实完全不需要token!删掉token试试,避免因为权限问题拉到不该拉的草稿数据 - useCdn:你已经设成
false了,这个没问题,关掉CDN就不会用Sanity的边缘缓存了
额外:如果想实现实时更新(不用刷新页面)
要是你想做到Sanity里改完内容,前端自动刷新,不用用户手动刷新,可以用Sanity的订阅功能:把BlogList改成客户端组件,然后在里面用client.subscribe监听数据变化,比如:
// BlogList.tsx 改成客户端组件,顶部加'use client' 'use client'; import { useEffect, useState } from 'react'; import { client } from '@/lib/sanity.client'; import { groq } from 'next-sanity'; const postQuery = groq`*[_type == "post" && !(_id in path("drafts.**"))] { ..., description, author->, categories[]-> } | order(_createdAt desc)`; export default function BlogList() { const [posts, setPosts] = useState([]); useEffect(() => { // 订阅数据变化 const subscription = client.subscribe(postQuery).subscribe({ next: (data) => setPosts(data), error: (err) => console.error('订阅出错:', err), }); // 组件卸载时取消订阅 return () => subscription.unsubscribe(); }, []); // 渲染逻辑... }
这样Sanity里的数据一更新,前端就会自动同步,不用刷新页面。
先把前三个解决方案试一遍,应该就能解决你的 stale 数据问题了!
备注:内容来源于stack exchange,提问作者Haris

