客户端已有未过期缓存时,如何在NextJS中跳过SSR
在Next.js + TanStack Query中实现缓存新鲜时跳过SSR
核心思路
借助TanStack Query的缓存状态判断数据是否新鲜,结合Next.js客户端导航特性,实现首次访问用SSR渲染、缓存未过期时直接复用客户端缓存跳过重复请求的效果。
具体实现
1. 封装自定义CachedLink组件
Next.js原生<Link>没有skipSsr属性,自己封装一个组件来实现缓存判断逻辑:
import Link from 'next/link'; import { useQueryClient } from '@tanstack/react-query'; import { useRouter } from 'next/router'; type CachedLinkProps = { href: string; todoId: string; children: React.ReactNode; }; export default function CachedLink({ href, todoId, children }: CachedLinkProps) { const queryClient = useQueryClient(); const router = useRouter(); // 检查对应todo的缓存是否存在且未过期 const isCacheFresh = queryClient.getQueryData(['todo', todoId]) && !queryClient.isQueryStale(['todo', todoId]); return ( <Link href={href} // 缓存新鲜时关闭预取,避免不必要的请求 prefetch={!isCacheFresh} onClick={(e) => { if (isCacheFresh) { e.preventDefault(); // 手动跳转到目标路由,触发客户端渲染 router.push(href); } }} > {children} </Link> ); }
2. 调整详情页的数据获取逻辑
保留SSR初始化逻辑的同时,让组件优先复用客户端缓存:
import { useQuery } from '@tanstack/react-query'; import { GetServerSideProps } from 'next'; export default function TodoDetail({ initialTodo }) { // useQuery会优先用initialTodo或客户端缓存,缓存过期才重新请求 const { data: todo } = useQuery({ queryKey: ['todo', initialTodo.id], queryFn: () => fetch(`/api/todos/${initialTodo.id}`).then(res => res.json()), initialData: initialTodo, }); return ( <div> <h1>{todo.title}</h1> <p>{todo.description}</p> </div> ); } // 首次访问/缓存过期时,通过SSR获取初始数据 export const getServerSideProps: GetServerSideProps = async (context) => { const { id } = context.params as { id: string }; const res = await fetch(`https://your-backend-api.com/todos/${id}`); const initialTodo = await res.json(); return { props: { initialTodo } }; };
3. 关键配置与说明
- 缓存新鲜度判断:
queryClient.isQueryStale(['todo', todoId])返回false时,说明缓存未过期,可跳过SSR - 全局缓存时长:可以在TanStack Query初始化时设置默认
staleTime,统一控制缓存新鲜周期:
import { QueryClient } from '@tanstack/react-query'; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 5 * 60 * 1000, // 5分钟内缓存视为新鲜,可按需调整 }, }, });
- 路由跳转逻辑:缓存新鲜时手动调用
router.push,触发Next.js的客户端路由更新,直接复用缓存数据渲染页面,不会触发getServerSideProps
内容的提问来源于stack exchange,提问作者Daniel Reina
相关产品推荐
相关产品推荐

