Menu

template.js

templateファイルはlayoutに似ており、layoutまたはページをラップします。ルート全体で永続化され状態を保持するlayoutとは異なり、templateには一意のキーが付与されるため、子Client Componentsはナビゲーション時に状態がリセットされます。

以下の場合に便利です。

  • ナビゲーション時にuseEffectを再同期させる必要がある場合。
  • ナビゲーション時に子Client Componentsの状態をリセットする必要がある場合。たとえば、入力フィールドです。
  • デフォルトフレームワーク動作を変更する場合。たとえば、layout内のSuspense境界は最初のロード時にのみフォールバックを表示しますが、templateはナビゲーション時に毎回表示します。

規約

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

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

ネスト構造の観点から、template.jsはlayoutとその子の間にレンダリングされます。簡略化した出力は以下の通りです。

Output
<Layout>
  {/* templateに一意のキーが付与されることに注意してください。 */}
  <Template key={routeParam}>{children}</Template>
</Layout>

プロップ

children(必須)

Templateはchildrenプロップを受け入れます。

Output
<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値は例示的なもので、アプリケーション内の値は異なる場合があります。

Output
<RootLayout>
  {/* app/template.tsx */}
  <Template key="/">
    <Page />
  </Template>
</RootLayout>

/aboutにナビゲートする場合(最初のセグメント変更)、ルートtemplateキーが変更され、リマウントされます。

Output
<RootLayout>
  {/* app/template.tsx */}
  <Template key="/about">
    <AboutPage />
  </Template>
</RootLayout>

/blogにナビゲートする場合(最初のセグメント変更)、ルートtemplateキーが変更され、リマウントされ、ブログレベルのtemplateがマウントされます。

Output
<RootLayout>
  {/* app/template.tsx (ルート) */}
  <Template key="/blog">
    {/* app/blog/template.tsx */}
    <Template key="/blog">
      <BlogIndexPage />
    </Template>
  </Template>
</RootLayout>

同じ最初のセグメント内の/blog/first-postにナビゲートする場合(子セグメント変更)、ルートtemplateキーは変更されませんが、ブログレベルのtemplateキーが変更され、リマウントされます。

Output
<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キーが変更され、再度リマウントされます。

Output
<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