[Next.js]Next.js のRouting処理 Dynamic Parallel and Intercepted Routesについ
前書き
なぜこの記事を書いたのか
最近、Next.js(14+)を学びながらデモプロジェクトを作成しています。ファイルシステムベースのルーターは私にとって新しいものです。基本的な概念は簡単に理解できましたが、Parallel RoutesやIntercepting Routesなどの高度な機能を理解するのに少し時間がかかりました。同じような疑問を持つ人がいるかもしれないと思い、みんなの助けになればと思ってこの記事を書きました。
Next.jsがファイスシステムベースのルーターを使用していることすでに知っていると仮定して、基本的な部分は省略し、Dynamic Routesのセクションから始めます。
Dynamic Routes
Dynamic Routesとは
Dynamic Routesは、URLの異なるパラメータに適用できるページ作成することを可能にします。単一の動的ルートを使用して、複数のシナリオを処理できます。
Dynamic Routesの作成
Dynamic Routesを作成するのはとても簡単で、ファイル名に角括弧を追加するだけです。例えば:
app/post/[slug]/page.tsx
これはブログ投稿用の動的ルートを作成し、[slug]
にはどのような値を入れることができます。
ルーターパラメータへのアクセス
ページコンポーネント内で、params
を使用してルートの動的な部分にアクセスできます。以下は簡単な例です:
// app\post\[slug]\page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getBlogPost(params.slug)
return (
<article>
<h1>{post.title}</h1>
<div>{{ post.content }}</div>
</article>
)
}
Catch-All Routes と Optional Catch-All Routes
先ほど作成したの動的ルートは[foldername]
という形式で命名され、ページコンポーネントで一つのパラメータを受け取ります。しかし、複数の動的ルートパラメータが必要な場合はどうでしょうか?例えば、app/shop/[category]/[id]/page.js
のような構造の場合。このような場合にCatch-All RoutesとOptional Catch-All Routes役立ちます。
Catch-All Routes
Next.jsは[...folderName]
という形式でCatch-All Routesを提供します。これにより、複数のパスセグメントを捕捉することができます。例えば:
app/shop/[...slug]/page.js
このルートは以下のようなパスにマッチします:
-
/shop/clothes
-
/shop/clothes/shirts
-
/shop/clothes/shirts/summer
// app\dynamic-routes\catch-all\[...slug]\page.tsx
export default function DRCatchAllPage({ params }: { params: { slug: string[] } }) {
const { slug } = params
return (
<div className="text-center">
Current Page is Dynamic Route Page with Catch-all Segments.
{/* slug will be an array: ['clothes', 'shirts', 'summer'] */}
<h1>Category: {slug.join(' > ')}</h1>
</div>
)
}
Catch-All Routes画面デモ
Optional Catch-All Routes
二重の角括弧を追加することで、Catch-All Routesはオプショナルにすることができます:
app/shop/[[...slug]]/page.js
このルートは以下のようなパスにマッチします:
-
/shop
-
/shop/clothes
-
/shop/clothes/shirts/summer
通常のCatch-All Routesとの違いは、このルートはパラメータなしでも動けます。
Optional Catch-All Routes画面デモ(パスありの場合)
Optional Catch-All Routes画面デモ(パスなしの場合)
// app\dynamic-routes\optional-catch-all\shop\[[...slug]]\page.tsx
export default function DROptCatchAllPage({ params }: { params: { slug?: string[] } }) {
return (
<div className="text-center">
Current Page is Dynamic Route Page with Optional Catch-all Segments.
<br />
The param info is: {params.slug ? params.slug.join('>') : 'empty info'}
</div>
)
}
Intercepting Routes
時には、ユーザーが特定のページに到達する前に、一時停止してリダイレクトしたいことがあります。Next.jsはこれを実現するためにIntercepting Routesを提供します。
Intercepting Routesとは
Intercepting Routesは、通常表示されるコンポーネントやページとは異なるものを表示するために、ルートを「intercept」する機能を提供します。
Intercepting Routesの作成
app/
├── intercepting/
│ └── [id]/
│ │ └── page.tsx
│ └── page.tsx
└── @modal/
└── (.)intercepting/
└── [id]/
│ └── page.tsx
└── default.tsx
この構造では、(.)intercepting
がIntercepting Routeです。(.)
は「同じセグメントのルートをインターセプトする」ことを意味します。
インターセプションの種類
Next.jsは異なる種類のインターセプションを提供しています:
-
(.)
- 同じセグメントをインターセプト -
(..)
- 親セグメントをインターセプト -
(...)
- すべてのセグメントをインターセプト
Intercepting Routes動作
Intercepting Routesの動作
- クリック時の挙動:
ユーザーが画面上のアイテムをクリックすると、URLは変更されますが、現在の画面はそのまま維持されます。その上で、新しいコンポーネントが表示されます。 - URL変更:
URLは即座に変更され、ターゲットページのURLになります。しかし、画面全体は更新されません。 - 画面の状態:
元の画面は背景に残り、その上に新しいコンポーネントが表示されます。これにより、ユーザーは元のコンテスト失うことなく、詳細情報を見ることや別の操作を行うのができます。 - リフレッシュ時の挙動:
ユーザーがページをリフレッシュすると、現在のURLに対応する完全なページが表示されます。
## Parallel Routes
キッチンで料理を作っているを想像して、コンロでパスタを茹でながら、オーブンでパンを焼きています。これがNext.jsのParallel Routesのようなものです。複数のことを同時に進行していますが、すべて同じ食事(この場合は画面ページ)の一部なのです。
Parallel Routesとは
Next.jsのParallel Routesは、同じレイアウト内で複数のページやコンポネントを同時にレンダリングすることが可能にします。
Parallel Routesの作成
Parallel Routesを作成するには、フォルダ名の前に@
記号を追加します。例えば:
parallel-routes/
│── layout.tsx
│── @pasta/
│ └── page.tsx
│── @bread/
└── page.tsx
この設定により、@pasta
と@bread
の両方のコンポネントを同じレイアウト内で並べて表示できます。
注意:
@
で始まるフォルダ名はslats
と呼ばれ、page.tsx
ファイルが含まれていてもルートとして認識されません。
Parallel Routesを実現するには、フォルダ名に@
記号を使用するだけでなく、layout.tsx
ファイルでこれらをchildren
と同様にパラメータとして受け取ります。
export default function ParallelRoutesLayout({
children,
pasta,
bread,
}: {
children: React.ReactNode
bread: React.ReactNode
pasta: React.ReactNode
}) {
return (
<>
{children}
<div className="flex text-center">
<div className="w-1/2 p-4">
<h1 className="text-2xl font-bold mb-4">pasta Side</h1>
{pasta}
</div>
<div className="w-1/2 p-4">
<h1 className="text-2xl font-bold mb-4">bread Side</h1>
{bread}
</div>
</div>
</>
)
}
Parallel Routesと通常のコンポネントは多くの共通点がありますが、最大の違いは、Parallel Routesにはルートのような機能が備わっていることだと思います。例えば:ローディング状態、エラー処理、デフォルトのフォールバックなどがあります。これらは通常のコンポネントでは手動で実装する必要があります。
Regular Parallel Routes
default.tsxについて
特定スロットにマッチするルートがない場合、フォールバックとして機能します。
各スロット内で必要があれば、独自のdefault.tsx
を持ちます。
parallel-routes/
│── layout.tsx
│── price/
│ └── page.tsx
│── @pasta/
│ └── page.tsx
│ └── default.tsx
│── @bread/
└── page.tsx
└── price/
└── page.tsx
この構造にように、スロット間は独立性があり、独自のルーティング構造を持ちます。
/parallel-routes/price
に移動した場合:
-
@bread
スロットにはprice
ルートが存在するため、コンテンツが正常に表示されます。 -
@price
スロットにはルートが存在しないため、default.tsx
が必要になります。
Parallel Routes with default info
おわりに
ここまでNext.jsのいろんなルーティングの種類について、ざっくりと説明してきました。
何か気になることがあれば、気軽にコメントしてくださいね!
参考
Discussion