ページとレイアウト

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

Next.js 13のApp Routerでは、ページ共有レイアウトテンプレートを簡単に作成するための新しいファイル規約が導入されました。このページでは、Next.jsアプリケーションでこれらの特殊なファイルを使用する方法を説明します。

ページ

ページは、ルートに対して一意のUIです。page.jsファイルからコンポーネントをエクスポートすることでページを定義できます。ネストされたフォルダを使用してルートを定義し、page.jsファイルを使用してルートを公開可能にします。

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>
}
// `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コンポーネントをdefaultエクスポートすることでレイアウトを定義できます。コンポーネントは、レンダリング時に子レイアウト(存在する場合)または子ページで埋められるchildrenプロップを受け入れる必要があります。

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>
  )
}

知っておくと良いこと:

  • 最上位のレイアウトはルートレイアウトと呼ばれます。この必須レイアウトはアプリケーションのすべてのページで共有されます。ルートレイアウトにはhtmlbodyタグを含める必要があります。
  • 任意のルートセグメントは独自のレイアウトを定義できます。これらのレイアウトはそのセグメント内のすべてのページで共有されます。
  • ルート内のレイアウトはデフォルトでネストされます。各親レイアウトはReactのchildrenプロップを使用して下位の子レイアウトをラップします。
  • ルートグループを使用して、特定のルートセグメントを共有レイアウトに含めたり除外したりできます。
  • レイアウトはデフォルトでサーバーコンポーネントですが、クライアントコンポーネントに設定できます。
  • レイアウトはデータを取得できます。詳細はデータ取得セクションを参照してください。
  • 親レイアウトとその子の間でデータを渡すことはできません。ただし、ルートで同じデータを複数回取得でき、Reactはパフォーマンスに影響を与えずにリクエストを自動的に重複排除します。
  • レイアウトは自身より下位のルートセグメントにアクセスできません。すべてのルートセグメントにアクセスするには、クライアントコンポーネントでuseSelectedLayoutSegmentまたはuseSelectedLayoutSegmentsを使用できます。
  • レイアウトには.js.jsx、または.tsxファイル拡張子を使用できます。
  • layout.jspage.jsファイルは同じフォルダに定義できます。レイアウトはページをラップします。

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

ルートレイアウトはappディレクトリの最上位で定義され、すべてのルートに適用されます。このレイアウトにより、サーバーから返される初期HTMLを変更できます。

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>
  )
}

知っておくと良いこと:

  • appディレクトリには必ずルートレイアウトを含める必要があります。
  • Next.jsは自動的に<html><body>タグを作成しないため、ルートレイアウトでこれらを定義する必要があります。
  • 組み込みのSEOサポートを使用して<head>HTML要素(例:<title>要素)を管理できます。
  • ルートグループを使用して複数のルートレイアウトを作成できます。例はこちらを参照してください。
  • ルートレイアウトはデフォルトでサーバーコンポーネントであり、クライアントコンポーネントに設定できません

pagesディレクトリからの移行: ルートレイアウトは_app.js_document.jsファイルを置き換えます。移行ガイドを参照してください。

レイアウトのネスト

フォルダ内(例:app/dashboard/layout.js)で定義されたレイアウトは、特定のルートセグメント(例:acme.com/dashboard)に適用され、それらのセグメントがアクティブなときにレンダリングされます。デフォルトでは、ファイル階層内のレイアウトはネストされており、childrenプロップを介して子レイアウトをラップします。

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

知っておくと良いこと:

  • ルートレイアウトのみが<html><body>タグを含めることができます。

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

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

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

ルートグループを使用して、特定のルートセグメントを共有レイアウトに含めたり除外したりできます。

テンプレート

テンプレートは、各子レイアウトまたはページをラップする点でレイアウトと似ています。ルート間で永続化され状態を保持するレイアウトとは異なり、テンプレートはナビゲーション時に子ごとに新しいインスタンスを作成します。つまり、テンプレートを共有するルート間をユーザーが移動すると、コンポーネントの新しいインスタンスがマウントされ、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>

<head>の変更

appディレクトリでは、組み込みのSEOサポートを使用してtitlemetaなどの<head>HTML要素を変更できます。

メタデータは、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>要素の重複排除などの高度な要件を自動的に処理するMetadata APIを使用してください。

利用可能なメタデータオプションについてはAPIリファレンスで詳しく学べます。