layout.js
layout
文件用于定义 Next.js 应用中的布局。
¥The layout
file is used to define a layout in your Next.js application.
export default function DashboardLayout({
children,
}: {
children: React.ReactNode
}) {
return <section>{children}</section>
}
export default function DashboardLayout({ children }) {
return <section>{children}</section>
}
根布局是根 app
目录中的最顶层布局。它用于定义 <html>
和 <body>
标签以及其他全局共享的 UI。
¥A root layout is the top-most layout in the root app
directory. It is used to define the <html>
and <body>
tags and other globally shared UI.
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
参考
¥Reference
属性
¥Props
children
(必需的)
¥children
(required)
布局组件应该接受并使用 children
属性。在渲染期间,children
将填充布局正在环绕的路由段。这些主要是子 布局(如果存在)或 页面 的组件,但也可能是其他特殊文件,如适用时的 加载中 或 错误。
¥Layout components should accept and use a children
prop. During rendering, children
will be populated with the route segments the layout is wrapping. These will primarily be the component of a child Layout (if it exists) or Page, but could also be other special files like Loading or Error when applicable.
params
(可选)
¥params
(optional)
从根段到该布局解析为包含 动态路由参数 对象的对象的 promise。
¥A promise that resolves to an object containing the dynamic route parameters object from the root segment down to that layout.
export default async function Layout({
params,
}: {
params: Promise<{ team: string }>
}) {
const team = (await params).team
}
export default async function Layout({ params }) {
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
prop 是一个 promise。你必须使用async/await
或 React 的use
函数来访问值。¥Since the
params
prop is a promise. You must useasync/await
or React'suse
function to access the values.-
在版本 14 及更早版本中,
params
是一个同步 prop。为了帮助实现向后兼容,你仍然可以在 Next.js 15 中同步访问它,但此行为将来会被弃用。¥In version 14 and earlier,
params
was a synchronous prop. To help with backwards compatability, you can still access it synchronously in Next.js 15, but this behavior will be deprecated in the future.
-
根布局
¥Root Layouts
app
目录必须包含根 app/layout.js
。
¥The app
directory must include a root app/layout.js
.
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html>
<body>{children}</body>
</html>
)
}
export default function RootLayout({ children }) {
return (
<html>
<body>{children}</body>
</html>
)
}
-
根布局必须定义
<html>
和<body>
标签。¥The root layout must define
<html>
and<body>
tags.-
你不应手动将
<head>
标签(例如<title>
和<meta>
)添加到根布局。相反,你应该使用 元数据 API,它会自动处理高级要求,例如流式传输和删除<head>
元素的重复数据。¥You should not manually add
<head>
tags such as<title>
and<meta>
to root layouts. Instead, you should use the Metadata API which automatically handles advanced requirements such as streaming and de-duplicating<head>
elements.
-
-
你可以使用 路由组 创建多个根布局。
¥You can use route groups to create multiple root layouts.
-
跨多个根布局导航将导致完整页面加载(与客户端导航相反)。例如,从使用
app/(shop)/layout.js
的/cart
导航到使用app/(marketing)/layout.js
的/blog
将导致整页加载。这仅适用于多个根布局。¥Navigating across multiple root layouts will cause a full page load (as opposed to a client-side navigation). For example, navigating from
/cart
that usesapp/(shop)/layout.js
to/blog
that usesapp/(marketing)/layout.js
will cause a full page load. This only applies to multiple root layouts.
-
注意事项
¥Caveats
布局未收到 searchParams
¥Layouts do not receive searchParams
与 页面 不同,布局组件不接收 searchParams
属性。这是因为共享布局是 导航期间不重新渲染,这可能会导致导航之间的 searchParams
过时。
¥Unlike Pages, Layout components do not receive the searchParams
prop. This is because a shared layout is not re-rendered during navigation which could lead to stale searchParams
between navigations.
使用客户端导航时,Next.js 仅自动渲染两个路由之间公共布局下方的页面部分。
¥When using client-side navigation, Next.js automatically only renders the part of the page below the common layout between two routes.
例如,在以下目录结构中,dashboard/layout.tsx
是 /dashboard/settings
和 /dashboard/analytics
的通用布局:
¥For example, in the following directory structure, dashboard/layout.tsx
is the common layout for both /dashboard/settings
and /dashboard/analytics
:
当从 /dashboard/settings
导航到 /dashboard/analytics
时,/dashboard/analytics
中的 page.tsx
将在服务器上重新渲染,而 dashboard/layout.tsx
不会重新渲染,因为它是两个路由之间共享的通用 UI。
¥When navigating from /dashboard/settings
to /dashboard/analytics
, page.tsx
in /dashboard/analytics
will rerender on the server, while dashboard/layout.tsx
will not rerender because it's a common UI shared between the two routes.
这种性能优化允许共享布局的页面之间的导航更快,因为只需运行页面的数据获取和渲染,而不是可能包括获取自己数据的共享布局的整个路由。
¥This performance optimization allows navigation between pages that share a layout to be quicker as only the data fetching and rendering for the page has to run, instead of the entire route that could include shared layouts that fetch their own data.
由于 dashboard/layout.tsx
不会重新渲染,布局服务器组件中的 searchParams
属性可能会在导航后变得过时。
¥Because dashboard/layout.tsx
doesn't re-render, the searchParams
prop in the layout Server Component might become stale after navigation.
相反,在布局中的客户端组件中使用 Page searchParams
prop 或 useSearchParams
钩子,该组件使用最新的 searchParams
在客户端上重新渲染。
¥Instead, use the Page searchParams
prop or the useSearchParams
hook in a Client Component within the layout, which is rerendered on the client with the latest searchParams
.
布局无法访问 pathname
¥Layouts cannot access pathname
布局无法访问 pathname
。这是因为布局默认是服务器组件,而 在客户端导航期间不要重新渲染 可能会导致 pathname
在导航之间变得过时。为了防止过时,Next.js 需要重新获取路由的所有分段,从而失去缓存的优势并增加导航上的 RSC 有效负载 大小。
¥Layouts cannot access pathname
. This is because layouts are Server Components by default, and don't rerender during client-side navigation, which could lead to pathname
becoming stale between navigations. To prevent staleness, Next.js would need to refetch all segments of a route, losing the benefits of caching and increasing the RSC payload size on navigation.
相反,你可以将依赖于路径名的逻辑提取到客户端组件中,并将其导入到你的布局中。由于客户端组件会在导航期间重新渲染(但不会重新获取),因此你可以使用 Next.js 钩子(例如 usePathname
)来访问当前路径名并防止过时。
¥Instead, you can extract the logic that depends on pathname into a Client Component and import it into your layouts. Since Client Components rerender (but are not refetched) during navigation, you can use Next.js hooks such as usePathname
to access the current pathname and prevent staleness.
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<>
<ClientComponent />
<main>{children}</main>
</>
)
}
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }) {
return (
<>
<ClientComponent />
<main>{children}</main>
</>
)
}
常见的 pathname
模式也可以使用 params
属性来实现。
¥Common pathname
patterns can also be implemented with params
prop.
有关详细信息,请参阅 examples 部分。
¥See the examples section for more information.
示例
¥Examples
基于 params
显示内容
¥Displaying content based on params
使用 动态路由段,你可以根据 params
属性显示或获取特定内容。
¥Using dynamic route segments, you can display or fetch specific content based on the params
prop.
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>
)
}
export default async function DashboardLayout({ children, params }) {
const { team } = await params
return (
<section>
<header>
<h1>Welcome to {team}'s Dashboard</h1>
</header>
<main>{children}</main>
</section>
)
}
在客户端组件中读取 params
¥Reading params
in Client Components
要在客户端组件(不能是 async
)中使用 params
,你可以使用 React 的 use
函数来读取 promise:
¥To use params
in a Client Component (which cannot be async
), you can use React's use
function to read the promise:
'use client'
import { use } from 'react'
export function Page({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = use(params)
}
'use client'
import { use } from 'react'
export function Page({ params }) {
const { slug } = use(params)
}
版本历史
¥Version History
版本 | 变化 |
---|---|
v15.0.0-RC | params 现在是一个 promise。codemod 可用。 |
v13.0.0 | layout 推出。 |