頁面與佈局

建議在繼續之前先閱讀路由基礎定義路由頁面。

Next.js 13 中的 App Router 引入了新的檔案慣例,可輕鬆建立頁面共享佈局模板。本頁將指導您如何在 Next.js 應用程式中使用這些特殊檔案。

頁面

頁面是路由中獨特的使用者介面。您可以透過從 page.js 檔案匯出元件來定義頁面。使用巢狀資料夾來定義路由,並使用 page.js 檔案使路由可公開存取。

app 目錄中新增 page.js 檔案來建立您的第一個頁面:

page.js 特殊檔案
// `app/page.tsx` 是 `/` URL 的使用者介面
export default function Page() {
  return <h1>Hello, Home page!</h1>
}

須知事項

佈局

佈局是多個頁面之間共享的使用者介面。在導航時,佈局會保留狀態、保持互動性且不會重新渲染。佈局也可以巢狀

您可以透過從 layout.js 檔案 default 匯出 React 元件來定義佈局。該元件應接受 children prop,該 prop 會在渲染時填入子佈局(如果存在)或子頁面。

layout.js 特殊檔案
export default function DashboardLayout({
  children, // 將是頁面或巢狀佈局
}: {
  children: React.ReactNode
}) {
  return (
    <section>
      {/* 在此包含共享 UI,例如標頭或側邊欄 */}
      <nav></nav>

      {children}
    </section>
  )
}

須知事項

  • 最頂層的佈局稱為根佈局。此必需佈局在應用程式的所有頁面中共享。根佈局必須包含 htmlbody 標籤。
  • 任何路由區段都可以選擇性地定義自己的佈局。這些佈局將在該區段的所有頁面中共享。
  • 路由中的佈局預設為巢狀。每個父佈局使用 React children prop 包裝其下方的子佈局。
  • 您可以使用路由群組來選擇特定路由區段加入或退出共享佈局。
  • 佈局預設為伺服器元件,但可以設為客戶端元件
  • 佈局可以取得資料。請參閱資料取得章節以取得更多資訊。
  • 無法在父佈局與其子元件之間傳遞資料。但是,您可以在路由中多次取得相同的資料,React 會自動去重複請求而不影響效能。
  • 佈局無法存取其下方的路由區段。要存取所有路由區段,可以在客戶端元件中使用 useSelectedLayoutSegmentuseSelectedLayoutSegments
  • 佈局可以使用 .js.jsx.tsx 副檔名。
  • 可以在同一資料夾中定義 layout.jspage.js 檔案。佈局將包裝頁面。

根佈局 (必需)

根佈局定義在 app 目錄的頂層,適用於所有路由。此佈局讓您可以修改從伺服器返回的初始 HTML。

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

須知事項

pages 目錄遷移: 根佈局取代了 _app.js_document.js 檔案。查看遷移指南

巢狀佈局

定義在資料夾內的佈局(例如 app/dashboard/layout.js)適用於特定路由區段(例如 acme.com/dashboard),並在這些區段處於活動狀態時渲染。預設情況下,檔案層級中的佈局是巢狀的,這意味著它們透過 children prop 包裝子佈局。

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

須知事項

  • 只有根佈局可以包含 <html><body> 標籤。

如果您將上述兩個佈局結合,根佈局 (app/layout.js) 將包裝儀表板佈局 (app/dashboard/layout.js),而儀表板佈局將包裝 app/dashboard/* 內的路由區段。

這兩個佈局將如下巢狀:

巢狀佈局 UI

您可以使用路由群組來選擇特定路由區段加入或退出共享佈局。

模板

模板與佈局類似,它們包裝每個子佈局或頁面。與跨路由保留狀態的佈局不同,模板在導航時會為每個子元件建立新實例。這意味著當使用者在共享模板的路由之間導航時,會掛載元件的新實例、重新建立 DOM 元素、不會保留狀態,且效果會重新同步。

在某些情況下,您可能需要這些特定行為,這時模板會是比佈局更合適的選擇。例如:

  • 依賴 useEffect 的功能(例如記錄頁面瀏覽)和 useState(例如每頁的反饋表單)。
  • 變更框架的預設行為。例如,佈局內的 Suspense Boundaries 僅在佈局首次載入時顯示後備內容,而在切換頁面時不會顯示。對於模板,後備內容會在每次導航時顯示。

可以透過從 template.js 檔案匯出預設 React 元件來定義模板。該元件應接受 children prop。

template.js 特殊檔案
export default function Template({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}

在巢狀結構方面,template.js 會在佈局與其子元件之間渲染。以下是簡化的輸出:

Output
<Layout>
  {/* 請注意模板具有唯一鍵。 */}
  <Template key={routeParam}>{children}</Template>
</Layout>

修改 <head>

app 目錄中,您可以使用內建 SEO 支援來修改 <head> HTML 元素,例如 titlemeta

可以在 layout.jspage.js 檔案中匯出 metadata 物件generateMetadata 函式 來定義元資料。

import { Metadata } from 'next'

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

export default function Page() {
  return '...'
}

須知事項:您不應手動將 <head> 標籤(例如 <title><meta>)新增至根佈局。相反,您應使用元資料 API,它會自動處理進階需求,例如串流和去重複 <head> 元素。

在 API 參考中了解更多可用的元資料選項。

On this page