layout.js

layout 檔案用於在您的 Next.js 應用程式中定義版面配置。

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

根版面配置 (root layout) 是根 app 目錄中最頂層的版面配置。它用於定義 <html><body> 標籤以及其他全域共享的 UI。

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

參考

屬性

children (必填)

版面配置元件應接受並使用 children 屬性。在渲染期間,children 將被填入該版面配置所包裹的路由區段。這些主要會是子 Layout (如果存在) 或 Page 的元件,但也可能是其他特殊檔案,如 LoadingError (當適用時)。

params (選填)

一個解析為物件的 Promise,該物件包含從根區段到該版面配置的 動態路由參數 物件。

export default async function Layout({
  params,
}: {
  params: Promise<{ team: string }>
}) {
  const { team } = await params
}
範例路由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

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html>
      <body>{children}</body>
    </html>
  )
}
  • 根版面配置 必須 定義 <html><body> 標籤。
    • 不應 手動將 <head> 標籤(如 <title><meta>)添加到根版面配置中。相反,您應該使用 Metadata API,它會自動處理進階需求,如串流和去重複 <head> 元素。
  • 您可以使用 路由群組 來建立多個根版面配置。
    • 多個根版面配置之間導航 會導致 完整頁面載入(與客戶端導航相反)。例如,從使用 app/(shop)/layout.js/cart 導航到使用 app/(marketing)/layout.js/blog 將導致完整頁面載入。這 適用於多個根版面配置。

注意事項

請求物件

版面配置在導航期間會被緩存在客戶端,以避免不必要的伺服器請求。

版面配置 不會重新渲染。它們可以被緩存和重複使用,以避免在頁面之間導航時進行不必要的計算。通過限制版面配置存取原始請求,Next.js 可以防止在版面配置中執行可能緩慢或昂貴的使用者代碼,這可能會對性能產生負面影響。

要存取請求物件,您可以在 伺服器元件 和函式中使用 headerscookies API。

import { cookies } from 'next/headers'

export default async function Layout({ children }) {
  const cookieStore = await cookies()
  const theme = cookieStore.get('theme')
  return '...'
}

查詢參數

版面配置在導航時不會重新渲染,因此它們無法存取可能過時的搜尋參數。

要存取更新的查詢參數,您可以使用頁面的 searchParams 屬性,或在客戶端元件中使用 useSearchParams 鉤子來讀取它們。由於客戶端元件在導航時會重新渲染,它們可以存取最新的查詢參數。

'use client'

import { useSearchParams } from 'next/navigation'

export default function Search() {
  const searchParams = useSearchParams()

  const search = searchParams.get('search')

  return '...'
}

路徑名稱

版面配置在導航時不會重新渲染,因此它們無法存取可能過時的路徑名稱。

要存取當前路徑名稱,您可以在客戶端元件中使用 usePathname 鉤子來讀取它。由於客戶端元件在導航時會重新渲染,它們可以存取最新的路徑名稱。

'use client'

import { usePathname } from 'next/navigation'

// 簡化的麵包屑邏輯
export default function Breadcrumbs() {
  const pathname = usePathname()
  const segments = pathname.split('/')

  return (
    <nav>
      {segments.map((segment, index) => (
        <span key={index}>
          {' > '}
          {segment}
        </span>
      ))}
    </nav>
  )
}

資料獲取

版面配置無法將資料傳遞給其 children。但是,您可以在路由中多次獲取相同的資料,並使用 React 的 cache 來去重請求而不影響性能。

或者,當在 Next.js 中使用 fetch 時,請求會自動去重。

export async function getUser(id: string) {
  const res = await fetch(`https://.../users/${id}`)
  return res.json()
}

存取子區段

版面配置無法存取其下方的路由區段。要存取所有路由區段,您可以在客戶端元件中使用 useSelectedLayoutSegmentuseSelectedLayoutSegments

'use client'

import Link from 'next/link'
import { useSelectedLayoutSegment } from 'next/navigation'

export default function NavLink({
  slug,
  children,
}: {
  slug: string
  children: React.ReactNode
}) {
  const segment = useSelectedLayoutSegment()
  const isActive = slug === segment

  return (
    <Link
      href={`/blog/${slug}`}
      // 根據連結是否處於活動狀態更改樣式
      style={{ fontWeight: isActive ? 'bold' : 'normal' }}
    >
      {children}
    </Link>
  )
}

範例

元數據

您可以使用 metadata 物件generateMetadata 函式 來修改 <head> HTML 元素,如 titlemeta

import type { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Next.js',
}

export default function Layout({ children }: { children: React.ReactNode }) {
  return '...'
}

須知:您 不應 手動將 <head> 標籤(如 <title><meta>)添加到根版面配置中。相反,請使用 Metadata API,它會自動處理進階需求,如串流和去重複 <head> 元素。

活動導航連結

您可以使用 usePathname 鉤子來確定導航連結是否處於活動狀態。

由於 usePathname 是一個客戶端鉤子,您需要將導航連結提取到一個客戶端元件中,然後可以將其導入到您的版面配置中:

'use client'

import { usePathname } from 'next/navigation'
import Link from 'next/link'

export function NavLinks() {
  const pathname = usePathname()

  return (
    <nav>
      <Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
        首頁
      </Link>

      <Link
        className={`link ${pathname === '/about' ? 'active' : ''}`}
        href="/about"
      >
        關於
      </Link>
    </nav>
  )
}

根據 params 顯示內容

使用動態路由區段 (dynamic route segments),您可以根據 params 屬性顯示或獲取特定內容。

export default async function DashboardLayout({
  children,
  params,
}: {
  children: React.ReactNode
  params: Promise<{ team: string }>
}) {
  const { team } = await params

  return (
    <section>
      <header>
        <h1>歡迎來到 {team} 的儀表板</h1>
      </header>
      <main>{children}</main>
    </section>
  )
}

在客戶端元件 (Client Components) 中讀取 params

要在客戶端元件 (無法使用 async) 中使用 params,可以使用 React 的 use 函數來讀取 promise:

'use client'

import { use } from 'react'

export default function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = use(params)
}

版本歷史

版本變更
v15.0.0-RCparams 現在是一個 promise。提供 codemod 工具。
v13.0.0引入 layout

On this page