Skip to main content

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
}
示例路由URLparams
app/dashboard/[team]/layout.js/dashboard/1Promise<{ team: '1' }>
app/shop/[tag]/[item]/layout.js/shop/1/2Promise<{ tag: '1', item: '2' }>
app/blog/[...slug]/layout.js/blog/1/2Promise<{ slug: ['1', '2'] }>
  • 由于 params prop 是一个 promise。你必须使用 async/await 或 React 的 use 函数来访问值。

    ¥Since the params prop is a promise. You must use async/await or React's use 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 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.

注意事项

¥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-RCparams 现在是一个 promise。codemod 可用。
v13.0.0layout 推出。