Next.js 14服务器组件点击按钮重新获取数据问题求助
解决Next.js 14服务器组件数据缓存与手动刷新问题
1. 先解决页面刷新时数据不更新的缓存问题
Next.js默认会缓存服务器组件的渲染结果和数据请求,可通过以下两种方式禁用缓存:
方式一:在服务器组件中全局禁用缓存
导入unstable_noStore并调用,强制每次请求都重新获取数据:
import getSummoner from "@/js/getSummoner"; import { unstable_noStore } from 'next/cache'; const Summoner = async ({ params }) => { unstable_noStore(); // 禁用缓存,确保每次请求都重新拉取数据 const search = params.search; let summoner = await getSummoner(search); if (summoner) { return ( <div className="flex flex-col items-center gap-2 mb-2"> <UpdateButton /> {/* 其他使用summoner数据的子组件 */} </div> ); } }; export default Summoner;
方式二:在数据请求中单独设置缓存策略
如果getSummoner内部用fetch调用API,直接在请求中配置缓存规则:
// getSummoner.js export default async function getSummoner(search) { const res = await fetch(`YOUR_API_ENDPOINT?search=${search}`, { cache: 'no-store', // 禁用该请求的缓存 // 也可使用 revalidate: 0 实现相同效果 // next: { revalidate: 0 } }); return res.json(); }
2. 添加手动刷新按钮(客户端组件触发服务器组件重渲染)
创建一个客户端组件UpdateButton,利用useRouter的refresh()方法触发路由刷新,迫使服务器组件重新执行并获取最新数据:
// components/UpdateButton.js 'use client'; import { useRouter } from 'next/navigation'; export default function UpdateButton() { const router = useRouter(); const handleRefresh = () => { router.refresh(); // 触发路由刷新,服务器组件会重新渲染并拉取最新数据 }; return ( <button onClick={handleRefresh} className="px-4 py-2 bg-blue-500 text-white rounded"> 刷新数据 </button> ); }
3. 进阶:用revalidateTag实现精准刷新(可选)
如果不想触发全页面刷新,可给数据请求添加标签,通过API路由触发精准缓存失效:
步骤1:给数据请求添加专属标签
// getSummoner.js export default async function getSummoner(search) { const res = await fetch(`YOUR_API_ENDPOINT?search=${search}`, { next: { tags: [`summoner-${search}`] } // 为该请求添加唯一标签 }); return res.json(); }
步骤2:创建用于触发缓存失效的API路由
// app/api/revalidate/route.js import { revalidateTag } from 'next/cache'; import { NextResponse } from 'next/server'; export async function POST(request) { const { tag } = await request.json(); revalidateTag(tag); // 使对应标签的缓存失效 return NextResponse.json({ revalidated: true, now: Date.now() }); }
步骤3:修改UpdateButton调用API实现精准刷新
// components/UpdateButton.js 'use client'; import { usePathname } from 'next/navigation'; export default function UpdateButton() { const pathname = usePathname(); const search = pathname.split('/').pop(); // 从当前路径提取search参数,需根据实际路由调整 const handleRefresh = async () => { await fetch('/api/revalidate', { method: 'POST', body: JSON.stringify({ tag: `summoner-${search}` }) }); router.refresh(); // 刷新页面加载最新数据 }; return ( <button onClick={handleRefresh} className="px-4 py-2 bg-blue-500 text-white rounded"> 刷新数据 </button> ); }
以上方案既保留了服务器组件的性能优势,又满足了API只能从后端发起的要求,同时实现了手动刷新数据的功能。
内容的提问来源于stack exchange,提问作者Alexis Scuderi
相关产品推荐
相关产品推荐

