You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js中React Query设置staleTime=Infinity仍重复请求问题

问题

在Next.js中使用getServerSideProps进行服务端数据获取时,从页面A跳转至页面B,发现具有相同queryKey的请求被重复发起。已将staleTime设置为Infinity,是否应该从缓存读取API响应?

示例代码:

export const getServerSideProps: GetServerSideProps = async (context) => {
  await queryClient.fetchQuery({
    queryKey: ['posts'],
    queryFn: () => fetchPosts(), // 从API获取文章的简单函数
    staleTime: Infinity,
  });

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

假设页面B也存在相同的getServerSideProps,期望在页面A与页面B之间切换时,React Query能使用queryKey: ['posts']的缓存数据,而非每次页面切换都重新请求。

解决方案

问题核心是服务端Query Client实例隔离:每次触发getServerSideProps时,Next.js会创建全新的React Query Client实例,不同页面的SSR请求用的是完全独立的缓存空间,就算设置了staleTime: Infinity,页面A的服务端缓存也无法被页面B的SSR过程读取。

要实现跨页面复用缓存,可从以下方向处理:

  • 客户端缓存优先策略
    在客户端组件中使用useQuery并保留staleTime: Infinity,服务端仅做首次数据预取脱水,后续页面切换完全依赖客户端的Query Client缓存(客户端缓存会在页面跳转时保留)。
    调整后代码示例:

    // 服务端getServerSideProps逻辑不变
    export const getServerSideProps: GetServerSideProps = async (context) => {
      const queryClient = new QueryClient();
      await queryClient.fetchQuery({ queryKey: ['posts'], queryFn: fetchPosts, staleTime: Infinity });
      return { props: { dehydratedState: dehydrate(queryClient) } };
    };
    
    // 客户端组件中
    const { data } = useQuery({
      queryKey: ['posts'],
      queryFn: fetchPosts,
      staleTime: Infinity,
    });
    
  • 共享服务端Query Client实例(需注意隔离)
    自定义全局Query Client单例,让所有getServerSideProps复用同一实例,但必须处理用户请求隔离,避免多用户缓存污染。比如结合Next.js的请求上下文存储用户专属缓存:

    // 创建全局Query Client单例
    let queryClient: QueryClient | null = null;
    
    export const getQueryClient = () => {
      if (!queryClient) {
        queryClient = new QueryClient({
          defaultOptions: { queries: { staleTime: Infinity } },
        });
      }
      return queryClient;
    };
    
    // 在getServerSideProps中使用
    export const getServerSideProps: GetServerSideProps = async (context) => {
      const queryClient = getQueryClient();
      // 生产环境需在此处添加用户隔离逻辑,比如基于context.req.headers.cookie区分缓存
      await queryClient.fetchQuery({ queryKey: ['posts'], queryFn: fetchPosts });
      return { props: { dehydratedState: dehydrate(queryClient) } };
    };
    
  • 改用静态生成(SSG)
    如果数据更新频率低,用getStaticProps+revalidate预生成页面,数据仅在构建或重新验证时请求一次,彻底避免重复请求。

最安全易维护的方案是客户端缓存优先,既保证首屏有预渲染数据,又能在页面切换时复用客户端缓存,避免不必要的服务端请求。

内容的提问来源于stack exchange,提问作者Nirmalya Ghosh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:43:17