跳至内容

layout.js

layout 文件用于在您的 Next.js 应用程序中定义布局。

app/dashboard/layout.tsx
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section>{children}</section>
}

**根布局**是根 app 目录中最顶层的布局。它用于定义 <html><body> 标签以及其他全局共享的 UI。

app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

参考

属性

children(必需)

布局组件应该接受并使用 children 属性。在渲染过程中,children 将填充布局正在包装的路由段。这些主要将是子 布局(如果存在)或 页面 的组件,但也可能是其他特殊文件,例如 加载错误(在适用情况下)。

params(可选)

一个解析为包含从根段到该布局的 动态路由参数 对象的对象的 Promise。

app/dashboard/[team]/layout.tsx
export default async function Layout({
  params,
}: {
  params: Promise<{ team: string }>
}) {
  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 属性是一个 Promise,因此您必须使用 async/await 或 React 的 use 函数来访问这些值。
    • 在版本 14 及更早版本中,params 是一个同步属性。为了帮助向后兼容,您仍然可以在 Next.js 15 中同步访问它,但此行为将在未来弃用。

根布局

app 目录**必须**包含一个根 app/layout.js

app/layout.tsx
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两个路由的公共布局。

File structure showing a dashboard folder nesting a layout.tsx file, and settings and analytics folders with their own pages

/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 并防止过时。

app/dashboard/layout.tsx
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属性显示或获取特定内容。

app/dashboard/layout.tsx
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。

app/page.tsx
'use client'
 
import { use } from 'react'
 
export function Page({ params }: { params: Promise<{ slug: string }> }) {
  const { slug } = use(params)
}

版本历史

版本更改
v15.0.0-RCparams现在是一个 Promise。提供了一个代码修改
v13.0.0引入了layout