layout.js
layout
文件用于在你的 Next.js 应用中定义布局。
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}
根布局是位于根 app
目录中的最顶层布局。它用于定义 <html>
和 <body>
标签以及其他全局共享的 UI。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
参考
Props
children
(必需)
布局组件应接受并使用 children
属性。在渲染期间,children
将被填充为布局所包裹的路由片段。这些主要是子级 Layout(如果存在)或 Page 的组件,但在适用的情况下也可能是其他特殊文件,如 Loading 或 Error。
params
(可选)
一个 Promise,解析为包含从根片段到该布局的 动态路由参数 对象。
export default async function Layout({
params,
}: {
params: Promise<{ team: string }>
}) {
const team = (await params).team
}
示例路由 | URL | params |
---|---|---|
app/dashboard/[team]/layout.js | /dashboard/1 | Promise<{ team: '1' }> |
app/shop/[tag]/[item]/layout.js | /shop/1/2 | Promise<{ tag: '1', item: '2' }> |
app/blog/[...slug]/layout.js | /blog/1/2 | Promise<{ slug: ['1', '2'] }> |
- 由于
params
属性是一个 promise,你必须使用async/await
或 React 的use
函数来访问这些值。- 在第 14 版及更早版本中,
params
是一个同步属性。为了向后兼容,你在 Next.js 15 中仍然可以同步访问它,但这个行为将在未来被弃用。
- 在第 14 版及更早版本中,
根布局
app
目录必须包含一个根 app/layout.js
。
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>{children}</body>
</html>
)
}
- 根布局必须定义
<html>
和<body>
标签。- 你不应手动添加
<head>
标签,如<title>
和<meta>
到根布局中。相反,你应该使用 Metadata API,它会自动处理流式传输和去重<head>
元素等高级需求。
- 你不应手动添加
- 你可以使用路由组创建多个根布局。
- 在多个根布局之间导航将导致完整页面加载(而不是客户端导航)。例如,从使用
app/(shop)/layout.js
的/cart
导航到使用app/(marketing)/layout.js
的/blog
将导致完整页面加载。这仅适用于多个根布局。
- 在多个根布局之间导航将导致完整页面加载(而不是客户端导航)。例如,从使用
注意事项
布局不接收 searchParams
与 Pages 不同,布局组件不接收 searchParams
属性。这是因为共享布局在导航期间不会重新渲染,这可能导致导航之间的 searchParams
过时。
使用客户端导航时,Next.js 自动只渲染两个路由之间共同布局以下的部分页面。
例如,在以下目录结构中,dashboard/layout.tsx
是 /dashboard/settings
和 /dashboard/analytics
两者的共同布局:
当从 /dashboard/settings
导航到 /dashboard/analytics
时,/dashboard/analytics
中的 page.tsx
将在服务器上重新渲染,而 dashboard/layout.tsx
将不会重新渲染,因为它是两个路由之间共享的 UI。
这种性能优化使得共享布局的页面之间的导航更快,因为只需运行页面的数据获取和渲染,而不是整个路由,包括可能获取自己数据的共享布局。
因为 dashboard/layout.tsx
不重新渲染,布局中的 Server Component 的 searchParams
属性可能在导航后变得过时。
相反,使用页面的 searchParams
属性或布局中的 Client Component 中的 useSearchParams
钩子,它将在客户端用最新的 searchParams
重新渲染。
布局无法访问 pathname
布局无法访问 pathname
。这是因为布局默认是 Server Components,并且在客户端导航期间不重新渲染,这可能导致导航之间的 pathname
变得过时。为了防止过时,Next.js 需要重新获取路由的所有片段,这会失去缓存的好处并增加导航时的 RSC payload 大小。
相反,你可以将依赖于 pathname 的逻辑提取到 Client Component 中,并将其导入到布局中。由于 Client Components 在导航期间重新渲染(但不重新获取),你可以使用 Next.js 钩子,如 usePathname
来访问当前 pathname 并防止过时。
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<ClientComponent />
{/* 其他布局 UI */}
<main>{children}</main>
</>
)
}
常见的 pathname
模式也可以用 params
属性实现。
更多信息请参见示例部分。
示例
基于 params
显示内容
使用动态路由片段,你可以基于 params
属性显示或获取特定内容。
export default async function DashboardLayout({
children,
params,
}: {
children: React.ReactNode
params: Promise<{ team: string }>
}) {
const { team } = await params
return (
<section>
<header>
<h1>欢迎来到 {team} 的仪表板</h1>
</header>
<main>{children}</main>
</section>
)
}
在 Client Components 中读取 params
要在 Client Component(不能是 async
)中使用 params
,你可以使用 React 的 use
函数来读取 promise:
'use client'
import { use } from 'react'
export default function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = use(params)
}
版本历史
版本 | 变更 |
---|---|
v15.0.0-RC | params 现在是一个 promise。代码模块可用。 |
v13.0.0 | 引入 layout 。 |