ページとレイアウト

続ける前に、ルーティングの基礎ルートの定義のページを読むことをお勧めします。

特別なファイル layout.jspage.js、および template.js を使用すると、ルートのUIを作成できます。このページでは、これらの特別なファイルをいつどのように使用するかを説明します。

ページ

ページはルートに固有のUIです。page.js ファイルからコンポーネントをデフォルトエクスポートすることでページを定義できます。

例えば、index ページを作成するには、app ディレクトリ内に page.js ファイルを追加します:

page.js 特別ファイル
// `app/page.tsx` は `/` URL のUIです
export default function Page() {
  return <h1>こんにちは、ホームページ!</h1>
}
// `app/page.js` は `/` URL のUIです
export default function Page() {
  return <h1>こんにちは、ホームページ!</h1>
}

さらにページを作成するには、新しいフォルダを作成し、その中に page.js ファイルを追加します。例えば、/dashboard ルートのページを作成するには、dashboard という新しいフォルダを作成し、その中に page.js ファイルを追加します:

// `app/dashboard/page.tsx` は `/dashboard` URL のUIです
export default function Page() {
  return <h1>こんにちは、ダッシュボードページ!</h1>
}
// `app/dashboard/page.js` は `/dashboard` URL のUIです
export default function Page() {
  return <h1>こんにちは、ダッシュボードページ!</h1>
}

知っておくと良いこと:

レイアウト

レイアウトは複数のルート間で共有されるUIです。ナビゲーション時に、レイアウトは状態を保持し、インタラクティブなまま再レンダリングされません。レイアウトはネストすることもできます。

layout.js ファイルからReactコンポーネントをデフォルトエクスポートすることでレイアウトを定義できます。コンポーネントはレンダリング時に子レイアウト(存在する場合)またはページが埋められる children プロップを受け入れる必要があります。

例えば、このレイアウトは /dashboard/dashboard/settings ページで共有されます:

layout.js 特別ファイル
export default function DashboardLayout({
  children, // ページまたはネストされたレイアウトになります
}: {
  children: React.ReactNode
}) {
  return (
    <section>
      {/* ヘッダーやサイドバーなどの共有UIを含める */}
      <nav></nav>

      {children}
    </section>
  )
}
export default function DashboardLayout({
  children, // ページまたはネストされたレイアウトになります
}) {
  return (
    <section>
      {/* ヘッダーやサイドバーなどの共有UIを含める */}
      <nav></nav>

      {children}
    </section>
  )
}

ルートレイアウト(必須)

ルートレイアウトは app ディレクトリの最上位で定義され、すべてのルートに適用されます。このレイアウトは必須で、サーバーから返される初期HTMLを変更できるように html タグと body タグを含める必要があります。

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>
        {/* レイアウトUI */}
        <main>{children}</main>
      </body>
    </html>
  )
}
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        {/* レイアウトUI */}
        <main>{children}</main>
      </body>
    </html>
  )
}

レイアウトのネスト

デフォルトでは、フォルダ階層内のレイアウトはネストされており、children プロップを介して子レイアウトをラップします。特定のルートセグメント(フォルダ)内に layout.js を追加することでレイアウトをネストできます。

例えば、/dashboard ルートのレイアウトを作成するには、dashboard フォルダ内に新しい layout.js ファイルを追加します:

ネストされたレイアウト
export default function DashboardLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return <section>{children}</section>
}
export default function DashboardLayout({ children }) {
  return <section>{children}</section>
}

上記の2つのレイアウトを組み合わせると、ルートレイアウト(app/layout.js)がダッシュボードレイアウト(app/dashboard/layout.js)をラップし、それが app/dashboard/* 内のルートセグメントをラップします。

2つのレイアウトは次のようにネストされます:

ネストされたレイアウトUI

知っておくと良いこと:

  • レイアウトには .js.jsx、または .tsx ファイル拡張子を使用できます。
  • ルートレイアウトのみが <html> タグと <body> タグを含めることができます。
  • 同じフォルダに layout.jspage.js ファイルが定義されている場合、レイアウトはページをラップします。
  • レイアウトはデフォルトでサーバーコンポーネントですが、クライアントコンポーネントに設定できます。
  • レイアウトはデータを取得できます。詳細はデータフェッチングセクションを参照してください。
  • 親レイアウトとその子の間でデータを渡すことはできません。ただし、ルートで同じデータを複数回フェッチでき、Reactはパフォーマンスに影響を与えずにリクエストを自動的に重複排除します。
  • レイアウトは自身より下のルートセグメントにアクセスできません。すべてのルートセグメントにアクセスするには、クライアントコンポーネントでuseSelectedLayoutSegmentまたはuseSelectedLayoutSegmentsを使用できます。
  • ルートグループを使用して、特定のルートセグメントを共有レイアウトに含めたり除外したりできます。
  • ルートグループを使用して複数のルートレイアウトを作成できます。例はこちらを参照してください。
  • pages ディレクトリからの移行: ルートレイアウトは_app.js_document.jsファイルを置き換えます。移行ガイドを参照してください。

テンプレート

テンプレートは各子レイアウトまたはページをラップする点でレイアウトと似ています。ルート間で持続し状態を保持するレイアウトとは異なり、テンプレートはナビゲーション時に子ごとに新しいインスタンスを作成します。つまり、テンプレートを共有するルート間をユーザーが移動すると、コンポーネントの新しいインスタンスがマウントされ、DOM要素が再作成され、状態は保持されず、エフェクトが再同期されます。

これらの特定の動作が必要な場合、テンプレートはレイアウトよりも適切な選択肢となります。例えば:

  • useEffect(ページビューのロギングなど)や useState(ページごとのフィードバックフォームなど)に依存する機能
  • デフォルトのフレームワーク動作を変更する場合。例えば、レイアウト内のサスペンス境界は、レイアウトが最初にロードされたときのみフォールバックを表示し、ページ切り替え時には表示しません。テンプレートでは、ナビゲーションごとにフォールバックが表示されます。

テンプレートは template.js ファイルからデフォルトのReactコンポーネントをエクスポートすることで定義できます。コンポーネントは children プロップを受け入れる必要があります。

template.js 特別ファイル
export default function Template({ children }: { children: React.ReactNode }) {
  return <div>{children}</div>
}
export default function Template({ children }) {
  return <div>{children}</div>
}

ネストに関して、template.js はレイアウトとその子の間にレンダリングされます。簡略化した出力は次のようになります:

出力
<Layout>
  {/* テンプレートには一意のキーが与えられます */}
  <Template key={routeParam}>{children}</Template>
</Layout>

メタデータ

app ディレクトリでは、メタデータAPIを使用して <head> HTML要素(titlemeta など)を変更できます。

メタデータは layout.js または page.js ファイルで metadata オブジェクトまたは generateMetadata 関数をエクスポートすることで定義できます。

import { Metadata } from 'next'

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

export default function Page() {
  return '...'
}
export const metadata = {
  title: 'Next.js',
}

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

知っておくと良いこと: <title><meta> などの <head> タグをルートレイアウトに手動で追加するべきではありません。代わりに、ストリーミングや <head> 要素の重複排除などの高度な要件を自動的に処理するメタデータAPIを使用してください。

利用可能なメタデータオプションの詳細はAPIリファレンスで確認できます