Skip to main content

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.

示例URLparams
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 root app/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 uses app/(shop)/layout.js to /blog that uses app/(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.0layout 推出。