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>
)
}
参考
属性
children
(必需)
布局组件应该接受并使用 children
属性。在渲染过程中,children
将填充布局正在包装的路由段。这些主要将是子 布局(如果存在)或 页面 的组件,但也可能是其他特殊文件,例如 加载 或 错误(在适用情况下)。
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>
)添加到根布局。相反,您应该使用 元数据 API,它会自动处理高级需求,例如流式传输和重复数据删除<head>
元素。
- 您**不应**手动将
- 您可以使用 路由组 创建多个根布局。
- 在**多个根布局之间导航**会导致**完整页面加载**(而不是客户端导航)。例如,从使用
app/(shop)/layout.js
的/cart
导航到使用app/(marketing)/layout.js
的/blog
将导致完整页面加载。这**仅**适用于多个根布局。
- 在**多个根布局之间导航**会导致**完整页面加载**(而不是客户端导航)。例如,从使用
注意事项
布局不接收searchParams
与页面不同,布局组件**不会**接收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
不会重新渲染,因此布局服务器组件中的searchParams
属性在导航后可能会变得**过时**。
相反,请在布局内的客户端组件中使用页面searchParams
属性或useSearchParams
钩子,该组件将在客户端使用最新的searchParams
重新渲染。
布局无法访问pathname
布局无法访问pathname
。这是因为布局默认情况下是服务器组件,并且在客户端导航期间不会重新渲染,这可能导致导航之间pathname
过时。为了防止过时,Next.js 需要重新获取路由的所有片段,从而失去缓存的优势并增加导航时的RSC 负载大小。
相反,您可以将依赖于 pathname 的逻辑提取到客户端组件中,并将其导入到您的布局中。由于客户端组件在导航期间会重新渲染(但不会重新获取),因此您可以使用 Next.js 钩子,例如usePathname
来访问当前 pathname 并防止过时。
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<ClientComponent />
{/* Other Layout 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>Welcome to {team}'s Dashboard</h1>
</header>
<main>{children}</main>
</section>
)
}
在客户端组件中读取params
要在客户端组件(不能是async
)中使用params
,您可以使用 React 的use
函数读取 Promise。
'use client'
import { use } from 'react'
export function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = use(params)
}
版本历史
版本 | 更改 |
---|---|
v15.0.0-RC | params 现在是一个 Promise。提供了一个代码修改。 |
v13.0.0 | 引入了layout 。 |
这有帮助吗?