template.js
templateファイルはlayoutに似ており、layoutまたはページをラップします。ルート全体で永続化され状態を保持するlayoutとは異なり、templateには一意のキーが付与されるため、子Client Componentsはナビゲーション時に状態がリセットされます。
以下の場合に便利です。
- ナビゲーション時に
useEffectを再同期させる必要がある場合。 - ナビゲーション時に子Client Componentsの状態をリセットする必要がある場合。たとえば、入力フィールドです。
- デフォルトフレームワーク動作を変更する場合。たとえば、layout内のSuspense境界は最初のロード時にのみフォールバックを表示しますが、templateはナビゲーション時に毎回表示します。
規約
templateはtemplate.jsファイルからデフォルトReactコンポーネントをエクスポートすることで定義できます。コンポーネントはchildrenプロップを受け入れる必要があります。
export default function Template({ children }: { children: React.ReactNode }) {
return <div>{children}</div>
}ネスト構造の観点から、template.jsはlayoutとその子の間にレンダリングされます。簡略化した出力は以下の通りです。
<Layout>
{/* templateに一意のキーが付与されることに注意してください。 */}
<Template key={routeParam}>{children}</Template>
</Layout>プロップ
children(必須)
Templateはchildrenプロップを受け入れます。
<Layout>
{/* templateに自動的に一意のキーが付与されることに注意してください。 */}
<Template key={routeParam}>{children}</Template>
</Layout>動作
- Server Components:デフォルトでは、templateはServer Componentsです。
- ナビゲーション時:templateは独自のセグメントレベルに対して一意のキーを受け取ります。そのセグメント(動的パラムを含む)が変更されるとリマウントされます。より深いセグメント内のナビゲーションではハイレベルのtemplateはリマウントされません。検索パラムはリマウントをトリガーしません。
- 状態のリセット:template内のClient Componentsはナビゲーション時に状態がリセットされます。
- エフェクトの再実行:
useEffectのようなエフェクトはコンポーネントがリマウントされると再同期されます。 - DOMのリセット:template内のDOM要素は完全に再作成されます。
ナビゲーション中とリマウント中のtemplates
このセクションでは、ナビゲーション中にtemplateがどのように動作するかを説明します。各ルート変更時にどのtemplateがリマウントされ、なぜそうなるのかをステップバイステップで示します。
このプロジェクトツリーを使用して説明します。
app
├── about
│ ├── page.tsx
├── blog
│ ├── [slug]
│ │ └── page.tsx
│ ├── page.tsx
│ └── template.tsx
├── layout.tsx
├── page.tsx
└── template.tsx
/から開始する場合、Reactツリーはおおよそこのようになります。
注意:例で示されている
key値は例示的なもので、アプリケーション内の値は異なる場合があります。
<RootLayout>
{/* app/template.tsx */}
<Template key="/">
<Page />
</Template>
</RootLayout>/aboutにナビゲートする場合(最初のセグメント変更)、ルートtemplateキーが変更され、リマウントされます。
<RootLayout>
{/* app/template.tsx */}
<Template key="/about">
<AboutPage />
</Template>
</RootLayout>/blogにナビゲートする場合(最初のセグメント変更)、ルートtemplateキーが変更され、リマウントされ、ブログレベルのtemplateがマウントされます。
<RootLayout>
{/* app/template.tsx (ルート) */}
<Template key="/blog">
{/* app/blog/template.tsx */}
<Template key="/blog">
<BlogIndexPage />
</Template>
</Template>
</RootLayout>同じ最初のセグメント内の/blog/first-postにナビゲートする場合(子セグメント変更)、ルートtemplateキーは変更されませんが、ブログレベルのtemplateキーが変更され、リマウントされます。
<RootLayout>
{/* app/template.tsx (ルート) */}
<Template key="/blog">
{/* app/blog/template.tsx */}
{/* このレベルで子セグメントが変更されたため、リマウントされます */}
<Template key="/blog/first-post">
<BlogPostPage slug="first-post" />
</Template>
</Template>
</RootLayout>/blog/second-postにナビゲートする場合(同じ最初のセグメント、異なる子セグメント)、ルートtemplateキーは変更されませんが、ブログレベルのtemplateキーが変更され、再度リマウントされます。
<RootLayout>
{/* app/template.tsx (ルート) */}
<Template key="/blog">
{/* app/blog/template.tsx */}
{/* 子セグメントの変更により再度リマウントされます */}
<Template key="/blog/second-post">
<BlogPostPage slug="second-post" />
</Template>
</Template>
</RootLayout>バージョン履歴
| バージョン | 変更内容 |
|---|---|
v13.0.0 | 導入時期:template |