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

Next.js技术问题:如何用getStaticProps获取菜单数据并传递给Layout?

解决方案

方案1:构建前预生成静态菜单数据文件

这是最彻底的SSG方案,直接在项目构建阶段把菜单数据写入本地文件,全局复用,无需每个页面单独请求。

  1. 编写数据拉取脚本
    在项目根目录创建scripts/fetch-menu.js:
const fs = require('fs');
const path = require('path');
const client = require('../path/to/your/sanity/client'); // 替换为你的Sanity客户端路径

async function fetchMenu() {
  const menu = await client.fetch('*[_type == "mainMenu"][0]'); // 替换为你的菜单查询语句
  const filePath = path.join(process.cwd(), 'src/data/menu.json');
  
  fs.writeFileSync(filePath, JSON.stringify(menu));
  console.log('菜单数据已预生成到src/data/menu.json');
}

fetchMenu().catch(err => {
  console.error('拉取菜单数据失败:', err);
  process.exit(1);
});
  1. 修改构建脚本
    在package.json中,给build命令添加前置脚本:
{
  "scripts": {
    "prebuild": "node scripts/fetch-menu.js",
    "build": "next build",
    // ...其他脚本
  }
}
  1. 在_app.js中引入并传递数据
// pages/_app.js
import Layout from '../components/Layout';
import menuData from '../src/data/menu.json';

function MyApp({ Component, pageProps }) {
  return (
    <Layout menu={menuData}>
      <Component {...pageProps} />
    </Layout>
  );
}

export default MyApp;

这样所有页面都会自动使用预生成的静态菜单数据,无需每个页面单独处理,完全符合SSG要求。

方案2:用高阶组件(HOC)封装菜单数据逻辑

如果不想修改构建流程,这个方案可以减少页面代码的重复度,避免每个页面都写重复的getStaticProps。

  1. 创建HOC文件
// components/withMenu.js
import client from '../path/to/your/sanity/client';

export const withMenu = (PageComponent) => {
  const WithMenuWrapper = (props) => <PageComponent {...props} />;

  WithMenuWrapper.getStaticProps = async (context) => {
    // 保留页面自身的getStaticProps逻辑(如果有的话)
    const pageProps = typeof PageComponent.getStaticProps === 'function'
      ? await PageComponent.getStaticProps(context)
      : { props: {} };

    // 获取菜单数据
    const menu = await client.fetch('*[_type == "mainMenu"][0]'); // 替换为你的查询

    return {
      props: {
        ...pageProps.props,
        menu,
      },
    };
  };

  return WithMenuWrapper;
};
  1. 在页面中使用HOC
// pages/your-page.js
import Layout from '../components/Layout';
import { withMenu } from '../components/withMenu';

function YourPage({ menu }) {
  return (
    <Layout menu={menu}>
      <article>页面内容...</article>
    </Layout>
  );
}

// 用HOC包裹页面组件,自动注入menu props
export default withMenu(YourPage);

这个方案虽然还是需要在页面中引入Layout,但无需重复编写菜单数据的获取逻辑,代码复用性更高。

方案3:升级到Next.js 13+ App Router(可选)

如果你的项目可以升级到App Router,Layout组件作为Server Component可以直接在构建时获取数据,完全符合SSG,且无需额外处理:

// app/layout.js
import client from '../path/to/your/sanity/client';

async function RootLayout({ children }) {
  // Server Component在构建时自动执行fetch,生成静态数据
  const menu = await client.fetch('*[_type == "mainMenu"][0]');

  return (
    <html lang="en">
      <body>
        <Header menu={menu} />
        {children}
      </body>
    </html>
  );
}

export default RootLayout;

App Router的Server Component默认会静态渲染,数据在构建时获取,完美解决你的痛点,但需要适配App Router的目录结构和语法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 11:45:38