メインコンテンツまでスキップ

ページとレイアウト

ルーティングの基礎ルーティングの定義のページを先に読むことをお勧めします。

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

ページ

ページとは、ルートに固有の UI です。page.jsファイルからコンポーネントをエクスポートすることで、ページを定義できます。ネストされたフォルダを使用してルートを定義し、page.jsファイルを使用してルートに一般的にアクセスできるようにします。

appディレクトリ内に page.js ファイルを追加して、最初のページを作成します:

page.js special file

app/page.tsx
// `app/page.tsx` is the UI for the `/` URL
export default function Page() {
return <h1>Hello, Home page!</h1>
}
app/dashboard/page.tsx
// `app/dashboard/page.tsx` is the UI for the `/dashboard` URL
export default function Page() {
return <h1>Hello, Dashboard Page!</h1>
}

Good to know:

  • ページは常にルートサブツリーリーフです。
  • .js, .jsx, .tsx の拡張子をページに使用することができます。
  • page.js ファイルはルートセグメントを一般公開するために必要です。
  • ページはデフォルトではServer Componentsですが、Client Componentに設定することもできます。
  • ページはデータをフェッチすることができます。詳細はData Fetchingセクションを参照してください。

レイアウト

レイアウトは、複数のページ間で共有される UI です。ナビゲーションの際、レイアウトは状態を保持し、インタラクティブであり続け、再レンダリングしません。レイアウトは入れ子にすることもできます。 レイアウトを定義するには、layout.jsファイルからdefault React コンポーネントをエクスポートします。このコンポーネントは children prop を受け取る必要があり、レンダリング時に子レイアウト(存在する場合)または子ページが入力されます。

layout.js special file

app/dashboard/layout.tsx
export default function DashboardLayout({
children, // will be a page or nested layout
}: {
children: React.ReactNode
}) {
return (
<section>
{/* Include shared UI here e.g. a header or sidebar */}
<nav></nav>

{children}
</section>
)
}

Good to know:

  • 一番上のレイアウトはルートレイアウトと呼ばれます。この必須レイアウトは、アプリケーション内のすべてのページで共有されます。ルートレイアウトは htmlbody タグを含まなければなりません。
  • 任意のルートセグメントはオプションで独自のLayoutを定義することができます。これらのレイアウトはそのセグメント内のすべてのページで共有されます。
  • ルート内のレイアウトはデフォルトで 入れ子 になっています。それぞれの親レイアウトは、React の children prop を使用して、その下の子レイアウトをラップします。
  • Route Groupsを使って、特定のルートセグメントを共有レイアウトに入れたり入れたりすることができます。
  • レイアウトはデフォルトではServer Componentsですが、Client Componentに設定することができます。
  • レイアウトはデータをフェッチすることができます。詳細はData Fetchingセクションを参照してください。
  • 親レイアウトとその子レイアウトの間でデータを渡すことはできません。しかし、ルート内で同じデータを複数回フェッチすることは可能で、React はパフォーマンスに影響を与えることなくリクエストを自動的にデデュープします。
  • レイアウトは現在のルートセグメントにアクセスできません。ルートセグメントにアクセスするには、クライアントコンポーネントでuseSelectedLayoutSegmentまたはuseSelectedLayoutSegmentsを使うことができます。
  • .js, .jsx, .tsx の拡張子をレイアウトに使用することができます。
  • layout.jspage.js ファイルを同じフォルダに定義することができます。レイアウトはページをラップします。

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

ルートレイアウトは app ディレクトリのトップレベルで定義され、すべてのルートに適用されます。このレイアウトによってサーバーから返される最初の HTML を修正できます。

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

Good to know:

  • appディレクトリにはルートレイアウトが必要です。
  • ルートレイアウトには、<html>タグと<body>タグを定義する必要があります。
  • ビルドイン SEO サポートを使って、<head> HTML 要素、たとえば<title>要素を管理することができます。
  • ルートグループを使って複数のルートレイアウトを作成することができます。例はこちらを参照してください。
  • ルートレイアウトはデフォルトではServer Componentであり、Client Componentには設定できません

pagesディレクトリからの移行: ルートレイアウトは_app.js_document.jsファイルを置き換えます。移行ガイドを見る

レイアウトの入れ子

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

Nested Layout

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

Good to know:

  • ルートレイアウトだけが<html>タグと<body>タグを含むことができます。

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

2 つのレイアウトはこのように入れ子になります。

Nested Layouts

Route Groupsを使って、特定のルート Segment を共有レイアウトに出し入れできます。

テンプレート

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

そのような特定の動作が必要な場合があり、テンプレートはレイアウトよりも適切なオプションです。例えば

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

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

template.js special file

app/template.tsx
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>
}

レイアウトとテンプレートを持つルート Segment のレンダリング出力はこのようになります。

Output
<Layout>
{/* Note that the template is given a unique key. */}
<Template key={routeParam}>{children}</Template>
</Layout>

<head> の修正

app ディレクトリでは、ビルドイン SEO サポート を使って titlemeta のような <head> HTML 要素を変更できます。

メタデータはlayout.js内のmetadata objectまたはgenerateMetadata関数をエクスポートすることで定義できます。 layout.jsまたはpage.jsファイルに記述します。

app/page.tsx
import { Metadata } from 'next'

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

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

Good to know: ルートレイアウトに <title><meta> のような <head> タグを手動で追加すべきではありません。その代わりに、Metadata API を使うべきです。この API は <head> 要素のストリーミングや重複除去といった高度な要求を自動的に処理します。

利用可能なメタデータのオプションについてはAPI リファレンスを参照してください。