使用Next.js <Link>跨页面更新数据的问题及解决方案咨询
解决方案:解决Next.js 预取导致tRPC缓存未更新的问题
1. 全面失效关联查询的tRPC缓存
你之前仅失效单个端点缓存,但数据变更会影响多个关联查询,必须同时失效所有相关端点的缓存。注意tRPC的缓存是基于「端点+查询参数」的键值对,失效时需匹配查询参数,或直接失效整个端点的所有缓存:
比如在更新场景的mutation中:
const updateScene = api.scene.update.useMutation({ async onSuccess(_, { sceneId, projectId }) { // 失效当前页面用到的scene查询(匹配参数) await api.scene.getByProjectIdElements.invalidate({ projectId }); // 失效scheduleboard页面用到的project查询(匹配参数) await api.project.getById.invalidate({ id: projectId }); // 若参数不确定,直接失效整个端点的所有缓存 // await api.scene.getByProjectIdElements.invalidate(); // await api.project.getById.invalidate(); }, });
2. 按需禁用预取
对数据更新频繁的页面链接,添加prefetch={false}属性,避免预取旧数据,同时保留客户端导航的速度优势:
<Link href={`/scenes/${sceneId}`} prefetch={false}> 场景详情 </Link>
3. 调整查询的缓存过期策略
给易变的查询设置staleTime: 0,让组件每次挂载都自动检查并获取最新数据,即使有预取缓存也会强制更新:
// scheduleboard.tsx 示例 const { data: projectData } = api.project.getById.useQuery( { id: projectId }, { enabled: !!projectId, staleTime: 0 } );
4. 确保全局共享tRPC客户端缓存
检查是否每个页面都独立创建了tRPC客户端实例——若如此会导致缓存隔离,mutation的失效操作无法跨页面生效。需在_app.tsx中通过withTRPC高阶组件全局注入客户端,让所有页面共享同一缓存池:
// _app.tsx import { withTRPC } from '@trpc/next'; import { createTRPCNext } from '@trpc/next'; import { appRouter } from '../server/trpc/router'; const trpc = createTRPCNext({ config() { return { url: '/api/trpc', }; }, }); function MyApp({ Component, pageProps }) { return <Component {...pageProps} />; } export default trpc.withTRPC(MyApp);
为什么之前的invalidate没生效?
核心原因通常是两个:
- 仅失效了单个端点,未覆盖关联的其他查询(比如更新场景后,
project.getById的缓存也需要失效); - invalidate时的参数和查询时的参数不匹配,tRPC无法定位到对应的缓存条目。
内容的提问来源于stack exchange,提问作者datawiz95
相关产品推荐
相关产品推荐

