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

如何在Next.js的_app中仅调用一次API并将数据传递给所需子组件

Next.js 全局顶层数据共享解决方案

针对你遇到的场景,以下是几个可落地的最优方案,可根据你的Next.js版本选择:

方案1:React Context + 全局单次请求(适配Pages Router/App Router全版本)

这是兼容性最高的方案,可实现仅调用一次API全应用共享数据:

  • 首先创建全局Context:
// contexts/GlobalDataContext.js
import { createContext, useContext, useEffect, useState } from 'react';

const GlobalDataContext = createContext();

export function GlobalDataProvider({ children }) {
  const [navData, setNavData] = useState(null);

  useEffect(() => {
    // 全局仅发起一次API请求
    fetch('/your/api/endpoint')
      .then(res => res.json())
      .then(data => setNavData(data));
  }, []);

  return (
    <GlobalDataContext.Provider value={{ navData }}>
      {children}
    </GlobalDataContext.Provider>
  );
}

export function useGlobalData() {
  return useContext(GlobalDataContext);
}
  • 在_app.js中包裹Provider,你的全局Layout不用改位置,保持全局引入即可:
// pages/_app.js
import { GlobalDataProvider } from '../contexts/GlobalDataContext';
import Layout from './layout';

export default function MyApp({ Component, pageProps }) {
  return (
    <GlobalDataProvider>
      <Layout>
        <Component {...pageProps} />
      </Layout>
    </GlobalDataProvider>
  );
}
  • 导航栏组件直接调用自定义Hook拿数据即可,不用逐层传props:
// components/Navbar.js
import { useGlobalData } from '../contexts/GlobalDataContext';

export default function Navbar() {
  const { navData } = useGlobalData();
  // 渲染搜索表单逻辑
}

如果需要服务端预取数据避免客户端请求的加载闪烁,可以在_app.js中添加getInitialProps全局请求一次,拿到数据后通过pageProps传入Context即可,_app.js本身是支持getInitialProps调用API的,不存在禁止请求的限制。

方案2:根Layout直接请求(适配Next.js 13+ App Router)

如果你已经升级到App Router版本,实现逻辑更简单:

  • 根app/layout.js本身是服务端组件,支持直接顶层await发起API请求,数据请求仅会在应用初始化时调用一次
  • 拿到数据后直接传递给Navbar组件即可,所有嵌套页面都会共享这个根布局的导航栏数据
// app/layout.js
import Navbar from './components/Navbar';
import Footer from './components/Footer';

async function getNavData() {
  const res = await fetch('your/api/endpoint', { next: { revalidate: 3600 } }); // 可配置缓存时间
  return res.json();
}

export default async function RootLayout({ children }) {
  const navData = await getNavData();
  return (
    <html>
      <body>
        <Navbar data={navData} />
        {children}
        <Footer />
      </body>
    </html>
  );
}

不推荐你之前考虑的两个方案的原因

  • 调整index.js作为全局入口不生效:index.js仅对应根路由/,访问其他路由如/about时不会加载该文件,其他页面的导航栏无法拿到数据
  • 每个页面单独调用API会造成冗余请求,切页时重复调用接口浪费资源,维护成本也更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 04:24:03