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

Next.js 13(App Router)动态路由向Layout传递Props方案

解决Next.js动态路由独立布局并传递Props的问题

方案一:通过路由分组隔离独立布局

Next.js的路由分组(括号包裹的目录)可让不同路由组使用各自的根布局,避免嵌套。调整项目结构如下:

/app
-/(site)
--/layout.tsx  # 原站点布局,负责首页等路由
--/page.tsx
-/(dynamic-slug)  # 新增独立路由组,承载动态[slug]路由
--/[slug]/page.tsx
--/[slug]/layout.tsx  # 动态路由专属独立布局

此时/(dynamic-slug)/[slug]/layout.tsx会成为该路由的根布局,不再嵌套/(site)/layout.tsx。接下来在这个独立布局中处理Props传递:

动态路由布局中获取并传递Props

// /app/(dynamic-slug)/[slug]/layout.tsx
import { Suspense } from 'react';
import { getSlugSettings } from '@/lib/data'; // 自定义数据获取函数
import SlugMasthead from '@/components/SlugMasthead';
import Foundation from '@/components/Foundation';

export default async function SlugLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { slug: string };
}) {
  // 根据slug获取对应数据作为Props
  const slugSettings = await getSlugSettings(params.slug);

  return (
    <html lang='en'>
      <body>
        <div className='flex min-h-screen flex-col'>
          <a className='sr-only' href='#mainContent'>
            Skip to content
          </a>
          <Suspense>
            {/* 向组件传递Props */}
            <SlugMasthead pageTitle={slugSettings.pageTitle} />
          </Suspense>
          <main className='flex flex-1 flex-col' id='mainContent'>
            {/* 若需子页面访问Props,用React Context传递 */}
            <SlugContext.Provider value={slugSettings}>
              <Suspense>{children}</Suspense>
            </SlugContext.Provider>
          </main>
          <Suspense>
            <Foundation menus={slugSettings.footerMenus} />
          </Suspense>
        </div>
      </body>
    </html>
  );
}

用React Context让子页面接收Props

创建Context文件:

// /app/context/slug.tsx
import { createContext, useContext } from 'react';

type SlugSettings = {
  pageTitle: string;
  footerMenus: MenuItem[];
  // 其他需传递的字段
};

const SlugContext = createContext<SlugSettings | undefined>(undefined);

export function SlugProvider({
  children,
  value,
}: {
  children: React.ReactNode;
  value: SlugSettings;
}) {
  return <SlugContext.Provider value={value}>{children}</SlugContext.Provider>;
}

export function useSlugContext() {
  const context = useContext(SlugContext);
  if (!context) {
    throw new Error('useSlugContext must be used within a SlugProvider');
  }
  return context;
}

之后在子页面中通过useSlugContext()即可获取布局传递的Props。

方案二:在现有布局中按路由分支处理(不调整路由结构)

若不想修改路由结构,可在/(site)/layout.tsx中根据当前路由判断,渲染不同布局内容并传递对应Props:

// /app/(site)/layout.tsx
import { Suspense } from 'react';
import { usePathname } from 'next/navigation';
import Masthead from '@/components/Masthead';
import SlugMasthead from '@/components/SlugMasthead';
import Foundation from '@/components/Foundation';
import { getSettings, getSlugSettings } from '@/lib/data';

export default async function SiteLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params?: { slug: string };
}) {
  const pathname = usePathname();
  const isDynamicSlug = params?.slug && pathname === `/${params.slug}`;

  // 根据路由获取对应数据
  const baseSettings = await getSettings();
  const slugSettings = isDynamicSlug ? await getSlugSettings(params.slug) : null;

  return (
    <html lang='en'>
      <body>
        <div className='flex min-h-screen flex-col'>
          <a className='sr-only' href='#mainContent'>
            Skip to content
          </a>
          <Suspense>
            {/* 按路由渲染不同组件并传递Props */}
            {isDynamicSlug && slugSettings ? (
              <SlugMasthead pageTitle={slugSettings.pageTitle} />
            ) : (
              <Masthead />
            )}
          </Suspense>
          <main className='flex flex-1 flex-col' id='mainContent'>
            <Suspense>{children}</Suspense>
          </main>
          <Suspense>
            <Foundation menus={slugSettings?.footerMenus || baseSettings.menus.footer} />
          </Suspense>
        </div>
      </body>
    </html>
  );
}

这种方式无需调整路由,但会增加主布局的逻辑复杂度,适合简单场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 17:35:57