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

Next.js中如何从Layout组件获取动态路由参数siteUrl?

Next.js中如何从Layout组件获取动态路由参数siteUrl?

我来帮你梳理下问题,然后一步步解决它~

首先,你遇到的核心问题是:父级布局无法直接访问子路由段的动态参数。你的(site)/layout.tsx是[siteUrl]目录的父布局,在Next.js App Router的规则里,路由参数是绑定到对应路由段的,父级布局只能拿到自己所在层级及以上的参数,子路由的参数不会自动向上传递,所以你在这个父布局里拿params.siteUrl自然会是undefined。

另外,你代码里把params的类型写成Promise<{ siteUrl: string }>也是个小错误——在服务器组件的布局/页面中,params是直接的普通对象,不需要用await去解析它。

下面给你两个可行的解决方案,优先推荐第一个:

方案一:把布局下移到动态路由段目录下

这是最直接的解决方式,把你的layout.tsx移动到app/(site)/[siteUrl]/目录下,让布局和动态参数[siteUrl]处于同一个路由层级。这样布局就能直接拿到siteUrl参数了。

修改后的代码会是这样:

import { notFound } from "next/navigation"
import "./globals.css"
import prisma from "@/lib/prisma"

export default async function SiteLayout({
    children,
    params
}: {
    children: React.ReactNode,
    params: { siteUrl: string } // 这里直接用普通对象类型,去掉Promise
}) {
    const { siteUrl } = params; // 直接解构,不需要await
    if (!siteUrl) {
        notFound()
    }

    const site = await prisma.site.findUnique({
        where: {
            siteUrl
        }
    })

    if (!site) {
        notFound()
    }

    // 这里可以把site通过上下文传递给子组件
    return (
        <html lang="es">
            <body>
                {children}
            </body>
        </html>
    )
}

如果你的(site)目录下还有其他非[siteUrl]的路由,你可以保留原来的(site)/layout.tsx作为顶级布局,让[siteUrl]/layout.tsx作为它的子布局,这样两个层级的布局各司其职。

方案二:用React Context传递数据给子组件

现在你希望把数据库查询逻辑放在布局里,然后把数据传给子组件(比如about-us/page.tsx),这时候用React Context是最合适的方式:

  1. 先创建一个上下文文件,比如app/components/SiteContext.tsx:
import { createContext, useContext } from 'react';
import type { Site } from '@prisma/client'; // 导入你的Site类型

const SiteContext = createContext<Site | null>(null);

export function SiteProvider({ children, site }: { children: React.ReactNode, site: Site }) {
    return (
        <SiteContext.Provider value={site}>
            {children}
        </SiteContext.Provider>
    );
}

export function useSite() {
    const context = useContext(SiteContext);
    if (!context) {
        throw new Error('useSite必须在SiteProvider内部使用');
    }
    return context;
}
  1. 然后在你的[siteUrl]/layout.tsx里使用这个Provider:
// 导入刚才创建的上下文
import { SiteProvider } from '@/app/components/SiteContext';
// ...其他导入

export default async function SiteLayout({
    children,
    params
}: {
    children: React.ReactNode,
    params: { siteUrl: string }
}) {
    const { siteUrl } = params;
    if (!siteUrl) {
        notFound()
    }

    const site = await prisma.site.findUnique({
        where: {
            siteUrl
        }
    })

    if (!site) {
        notFound()
    }

    return (
        <html lang="es">
            <body>
                <SiteProvider site={site}>
                    {children}
                </SiteProvider>
            </body>
        </html>
    )
}
  1. 最后在about-us/page.tsx里就可以直接获取site数据,不用重复查询数据库了:
import { useSite } from '@/app/components/SiteContext';

export default function AboutUsPage() {
    const site = useSite();
    
    return (
        <div>
            <h1>关于我们 - {site.name}</h1>
            {/* 其他内容 */}
        </div>
    )
}

这样就能完美实现你想要的:在布局里统一查询数据,然后把数据传递给所有子组件使用。

备注:内容来源于stack exchange,提问作者Tincho.UY

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 09:03:03