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

React+Next.js搭配Firestore时跳转页面后保留已获取数据避免重复读取的实现方法

实现方案

你可以根据业务场景选择以下几种实现方式,均可以避免重复触发Firestore读请求:

方案1:全局状态管理(内存缓存)

适用场景:仅需要同一次打开页面的会话内复用数据,允许刷新页面后重新请求。
Next.js客户端路由跳转时,全局状态不会随页面组件卸载销毁,只要把拉取到的counts存在全局状态里,返回页面时直接读取已有值即可,无需二次请求。以下用轻量状态库Zustand为例:

// store/countStore.js 全局状态定义
import { create } from 'zustand'

const useCountStore = create((set) => ({
  counts: null,
  setCounts: (data) => set({ counts: data })
}))

修改原有页面的逻辑:

import useCountStore from '@/store/countStore'

// 页面组件内
const { counts, setCounts } = useCountStore()

useEffect(() => {
  // 已有数据直接跳过请求
  if (counts) return
  const newObj = {};
  FB.getAllFiles()
    .then((snapshot) => {
      snapshot.forEach((doc) => {
        const data = doc.data();
        newObj[data["name"]] = data["count"];
      });
      setCounts(newObj);
    })
    .catch((e) => console.log(e));
}, [counts, setCounts]);

你也可以用React Context、Redux等其他全局状态方案实现,逻辑一致。

方案2:持久化本地缓存

适用场景:希望用户刷新页面后也无需重新请求,允许数据有一定的更新延迟。
可以把数据存在localStorage/sessionStorage里,还可以配置过期时间避免数据长期不更新:

const [counts, setCounts] = useState(null)

useEffect(() => {
  // 优先读取本地缓存
  const cachedCounts = localStorage.getItem('fileCounts')
  const cacheExpireTime = localStorage.getItem('fileCountsExpire')
  // 缓存存在且未过期直接复用
  if (cachedCounts && cacheExpireTime && Date.now() < Number(cacheExpireTime)) {
    setCounts(JSON.parse(cachedCounts))
    return
  }
  const newObj = {};
  FB.getAllFiles()
    .then((snapshot) => {
      snapshot.forEach((doc) => {
        const data = doc.data();
        newObj[data["name"]] = data["count"];
      });
      setCounts(newObj);
      // 写入缓存,设置1小时过期
      localStorage.setItem('fileCounts', JSON.stringify(newObj))
      localStorage.setItem('fileCountsExpire', String(Date.now() + 3600 * 1000))
    })
    .catch((e) => console.log(e));
}, []);

方案3:使用数据请求库内置缓存

适用场景:项目中有大量请求需要统一管理,希望省去手动维护缓存的成本。
TanStack Query(原React Query)、SWR这类数据请求库原生支持请求缓存、新鲜时间配置,还自带错误重试、自动重验证等能力。以下用TanStack Query为例:
首先在项目根组件配置Provider:

// _app.jsx / app/layout.jsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'

const queryClient = new QueryClient()

export default function App({ Component, pageProps }) {
  return (
    <QueryClientProvider client={queryClient}>
      <Component {...pageProps} />
    </QueryClientProvider>
  )
}

页面内使用:

import { useQuery } from '@tanstack/react-query'

// 封装请求逻辑
const getFileCounts = async () => {
  const newObj = {}
  const snapshot = await FB.getAllFiles()
  snapshot.forEach((doc) => {
    const data = doc.data()
    newObj[data["name"]] = data["count"]
  })
  return newObj
}

// 页面组件内
const { data: counts, isLoading, error } = useQuery({
  queryKey: ['fileCounts'], // 缓存的唯一标识
  queryFn: getFileCounts,
  staleTime: 3600 * 1000, // 1小时内数据视为新鲜,不会重复发起请求
  cacheTime: 24 * 3600 * 1000 // 缓存最多保留24小时
})

如果后续有数据更新的需求,可以在更新逻辑中主动触发对应queryKey的缓存失效,即可拉取最新数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.16 00:57:00