Next/React应用如何实现数据仅加载一次,仅页面真实重载时重新请求?
Next.js 全局单次加载API数据的实现方案
你遇到的重复请求问题,通常是因为将请求逻辑放在了
_app.js的getInitialProps/getServerSideProps这类每次路由切换都会触发的生命周期中,或是客户端请求没有加缓存判断导致的。
方案1:客户端状态缓存(全版本通用,最推荐)
用全局状态管理存储请求到的数据,仅当数据不存在时发起请求,页面刷新后状态自动重置,完全符合需求。你可以用轻量状态库Zustand实现,也可以用React Context、Redux等替代:
- 第一步:创建全局存储
// stores/globalData.js import { create } from 'zustand' const useGlobalDataStore = create((set) => ({ globalData: null, fetchGlobalData: async () => { const res = await fetch('你的API地址') const data = await res.json() set({ globalData: data }) } })) export default useGlobalDataStore
- 第二步:在
_app.js(Pages Router)或根layout(App Router)中添加请求逻辑
// pages/_app.js(Pages Router示例) import { useEffect } from 'react' import useGlobalDataStore from '../stores/globalDataStore' export default function MyApp({ Component, pageProps }) { const { globalData, fetchGlobalData } = useGlobalDataStore() // 仅当全局数据不存在时才发起请求 useEffect(() => { if (!globalData) fetchGlobalData() }, [globalData, fetchGlobalData]) return <Component {...pageProps} /> }
后续任意组件都可以通过这个store直接读取全局数据,不会重复发起请求。
方案2:静态变量缓存(服务端请求场景适用)
如果你需要在服务端获取数据,避免_app.js的getInitialProps重复请求,可以用静态变量缓存结果:
// pages/_app.js import App from 'next/app' // 定义静态缓存变量 let cachedGlobalData = null MyApp.getInitialProps = async (appContext) => { const appProps = await App.getInitialProps(appContext) // 仅缓存为空时发起请求 if (!cachedGlobalData) { const res = await fetch('你的API地址') cachedGlobalData = await res.json() } return { ...appProps, globalData: cachedGlobalData } } function MyApp({ Component, pageProps, globalData }) { // 可以把globalData通过Context传递给子组件使用 return <Component {...pageProps} /> } export default MyApp
注意:该方案的缓存是服务端进程级别的,多实例部署时每个实例会独立请求一次数据,无其他副作用。
方案3:轻量场景直接使用window对象挂载
如果不想引入状态管理,也可以直接把数据挂载到全局window对象上,页面刷新时window会自动重置:
// pages/_app.js import { useEffect, useState } from 'react' export default function MyApp({ Component, pageProps }) { const [globalData, setGlobalData] = useState(null) useEffect(() => { if (!window.__GLOBAL_APP_DATA__) { fetch('你的API地址') .then(res => res.json()) .then(data => { window.__GLOBAL_APP_DATA__ = data setGlobalData(data) }) } else { setGlobalData(window.__GLOBAL_APP_DATA__) } }, []) return <Component {...pageProps} globalData={globalData} /> }
小提示:如果使用Next.js 13+的App Router,直接在根服务端Layout中发起的
fetch请求默认会被全局缓存,全应用复用,也能实现减少重复请求的效果。
内容的提问来源于stack exchange,提问作者quikina
相关产品推荐
相关产品推荐

