layout.js
布局是在路由之间共享的 UI。
¥A layout is UI that is shared between routes.
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>
)
}
属性
¥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)
从根段到该布局的 动态路由参数 对象。
¥The dynamic route parameters object from the root segment down to that layout.
示例 | URL | params |
---|---|---|
app/dashboard/[team]/layout.js | /dashboard/1 | { team: '1' } |
app/shop/[tag]/[item]/layout.js | /shop/1/2 | { tag: '1', item: '2' } |
app/blog/[...slug]/layout.js | /blog/1/2 | { slug: ['1', '2'] } |
例如:
¥For example:
export default function ShopLayout({
children,
params,
}: {
children: React.ReactNode
params: {
tag: string
item: string
}
}) {
// URL -> /shop/shoes/nike-air-max-97
// `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
return <section>{children}</section>
}
export default function ShopLayout({ children, params }) {
// URL -> /shop/shoes/nike-air-max-97
// `params` -> { tag: 'shoes', item: 'nike-air-max-97' }
return <section>{children}</section>
}
很高兴知道
¥Good to know
根布局
¥Root Layouts
-
app
目录必须包含根app/layout.js
。¥The
app
directory must include a rootapp/layout.js
. -
根布局必须定义
<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.
-
布局未收到 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
属性或 useSearchParams
钩子,该组件会使用最新的 searchParams
在客户端上重新渲染。
¥Instead, use the Page searchParams
prop or the useSearchParams
hook in a Client Component, which is re-rendered 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 />
{/* Other Layout UI */}
<main>{children}</main>
<>
)
}
import { ClientComponent } from '@/app/ui/ClientComponent'
export default function Layout({ children }) {
return (
<>
<ClientComponent />
{/* Other Layout UI */}
<main>{children}</main>
<>
)
}
常见的 pathname
模式也可以使用 params
属性来实现。
¥Common pathname
patterns can also be implemented with params
prop.
有关详细信息,请参阅 examples 部分。
¥See the examples section for more information.
版本历史
¥Version History
版本 | 变化 |
---|---|
v13.0.0 | layout 推出。 |