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

使用react-query与Next.js时能否实现服务端数据缓存?

React Query 默认是客户端状态管理库,服务端每次执行页面渲染逻辑(包括getStaticProps)时如果每次新建QueryClient实例,缓存是无法跨页面/跨请求共享的。你之前只通过initialData传递数据到客户端,仅能避免客户端重复请求,无法减少服务端到Firebase的请求次数。

方案1:轻量服务端内存缓存(最易实现)

直接在服务端用内存缓存工具封装Firebase请求逻辑,不管哪个页面的getStaticProps调用,都优先走缓存,命中就不用请求Firebase。

  • 第一步:安装轻量缓存库
    npm install node-cache
  • 第二步:封装全局缓存实例和Firebase请求方法
// utils/serverCache.js
import NodeCache from 'node-cache';
// 配置缓存有效期,示例为5分钟,可根据项目更新频率调整
const firebaseCache = new NodeCache({ stdTTL: 300 });
export default firebaseCache;
// services/projectService.js
import firebaseCache from '../utils/serverCache';
import { db } from '../firebase/config';

export const fetchAllProjects = async () => {
  const CACHE_KEY = 'projects:all';
  // 优先读取缓存
  const cachedProjects = firebaseCache.get(CACHE_KEY);
  if (cachedProjects) return cachedProjects;
  // 缓存未命中再请求Firebase
  const projectSnapshot = await db.collection('projects').get();
  const projects = projectSnapshot.docs.map(doc => ({
    id: doc.id,
    ...doc.data()
  }));
  // 写入缓存
  firebaseCache.set(CACHE_KEY, projects);
  return projects;
};
  • 第三步:所有页面的getStaticProps直接调用封装后的方法即可
// pages/projects.jsx 和 pages/projects/[id].jsx 的getStaticProps通用
import { fetchAllProjects } from '../services/projectService';

export async function getStaticProps() {
  const projects = await fetchAllProjects();
  // 其他逻辑处理,比如[id].jsx可以直接从全量projects里过滤对应id的项目
  return {
    props: { projects },
    revalidate: 300 // 和缓存有效期保持一致即可
  };
}
方案2:React Query 服务端预取+Hydration(兼顾客户端和服务端缓存)

如果想要同时复用React Query的缓存能力,避免客户端重复请求,可以用React Query官方的脱水/注水能力,同时复用服务端的QueryClient实例实现缓存共享。

  • 第一步:封装通用QueryClient生成逻辑
// utils/queryClient.js
import { QueryClient } from '@tanstack/react-query';

// 服务端全局复用同一个实例,避免每次请求新建导致缓存失效
let serverQueryClient;
export const getServerQueryClient = () => {
  if (!serverQueryClient) {
    serverQueryClient = new QueryClient({
      defaultOptions: {
        queries: {
          cacheTime: 1000 * 60 * 5, // 缓存5分钟
        },
      },
    });
  }
  return serverQueryClient;
};

// 客户端独立生成实例即可
export const createClientQueryClient = () => new QueryClient();
  • 第二步:在getStaticProps中预取数据
import { dehydrate } from '@tanstack/react-query/hydration';
import { getServerQueryClient } from '../utils/queryClient';
import { fetchAllProjects } from '../services/projectService';

export async function getStaticProps() {
  const queryClient = getServerQueryClient();
  // 预取数据,缓存存在时不会重复执行fetchAllProjects请求Firebase
  await queryClient.prefetchQuery(['projects'], fetchAllProjects);
  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
    revalidate: 300,
  };
}
  • 第三步:在_app.jsx中完成客户端注水
import { Hydrate, QueryClientProvider } from '@tanstack/react-query';
import { createClientQueryClient } from '../utils/queryClient';

export default function MyApp({ Component, pageProps }) {
  const queryClient = createClientQueryClient();
  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <Component {...pageProps} />
      </Hydrate>
    </QueryClientProvider>
  );
}
  • 第四步:页面组件中直接用useQuery即可,不需要再传initialData
const { data: projects } = useQuery(['projects'], fetchAllProjects);
补充说明

如果你的项目部署在Serverless环境,实例冷启动会清空内存缓存,需要跨实例共享缓存的话可以把node-cache替换为Redis即可。

内容的提问来源于stack exchange,提问作者Shiladitya Thakur

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 06:45:03