Next.js 13使用revalidate时需刷新两次才显示数据更新问题
问题
我通过以下REST请求在Next.js页面填充数据(使用版本13.4.13):
// src/app/page.js const Home = async () => { const globalData = await getGlobalData(); return ( <main> <SomeComponent data={globalData} /> </main> ); };
数据来自数据库,我确认数据库信息已于昨日更新,但页面加载时仍显示旧数据,必须刷新两次后才会展示新数据。此后每次页面加载都会显示新数据,但如果数据库数据在数小时前更新,又需要刷新两次才能看到。
我设置了每60秒刷新一次的逻辑,代码如下:
export const refresh = (seconds = 60) => ({ next: { revalidate: seconds }}); export const getGlobalData = async () => { try { const res = await fetch(`${myDomain}/api/global`, refresh()); if (!res.ok) { console.log('Failed'); return {}; } return await res.json(); } catch (e) { console.log(`Connection refused`); } return {}; };
分析与解决方案
核心原因
- Next.js静态缓存机制:App Router默认会预渲染页面并生成静态缓存。第一次刷新时,Next.js先返回缓存的旧页面,同时在后台触发重新验证流程;第二次刷新时,新生成的缓存才会生效,所以能看到最新数据。
- revalidate配置的局限性:60秒的重新验证周期是从页面首次生成或上次验证完成开始计算的。如果数据库更新时,缓存还没到自动刷新的时间点,就不会主动拉取新数据,必须手动刷新触发验证。
解决办法
- 强制动态渲染:如果需要每次页面加载都获取最新数据,直接在
page.js顶部添加动态渲染配置,跳过静态缓存:// src/app/page.js export const dynamic = 'force-dynamic'; const Home = async () => { const globalData = await getGlobalData(); return ( <main> <SomeComponent data={globalData} /> </main> ); }; - 调整fetch的缓存策略:如果想保留部分缓存特性,但需要按需获取最新数据,可以把fetch的revalidate设为0,让每次请求都拉取最新数据:
export const getGlobalData = async () => { try { const res = await fetch(`${myDomain}/api/global`, { next: { revalidate: 0 } }); if (!res.ok) { console.log('Failed'); return {}; } return await res.json(); } catch (e) { console.log(`Connection refused`); } return {}; }; - 手动触发缓存刷新:如果数据库更新时有触发机制(比如webhook),可以调用Next.js的
revalidatePathAPI手动生成新缓存,不用等自动revalidate或手动刷新:
在API路由或数据库更新的处理逻辑中添加:import { revalidatePath } from 'next/cache'; // 数据库更新完成后调用该函数 async function triggerCacheRefresh() { revalidatePath('/'); // 重新生成首页的缓存 }
内容的提问来源于stack exchange,提问作者karvai
相关产品推荐
相关产品推荐

