Next.jsのIntercepting Routesのスコープを知らずつまづいた
公開日:
タグ:
- #Next.js
Intercepting Routesとは
Interceptには「横取りする」という意味があります。
Intercepting Routes は、本来は別ページとして表示されるルートを、現在のレイアウト内に割り込ませて表示できる仕組みです。
これによりURLは変更されつつも、ページ遷移を挟まずに現在のレイアウト上に別のUI(例:モーダル)を表示することができます。
良く例として挙げられるのがWebで見たときのInstagramです。 プロフィールから投稿をクリックしたときは、URLを変更しながらモーダル表示で投稿内容を表示し、投稿内容のURLに直接リンクしたときは、別ページとして表示するような構築ができます。
実際に試した実装方法
app/
├── layout.tsx
├── page.tsx
├── @modal/
│ └── (.)photo/[id]/page.tsx
└── photo/
└── [id]/page.tsx
TOPに画像の一覧を作成して、クリックしたら情報を取得するようなページを作成しました。

export default function BaseLayout({
children,
modal,
}: Readonly<{
children: React.ReactNode;
modal?: React.ReactNode;
}>) {
return (
<>
{children}
{modal}
</>
);
}
@modal という Parallel Routes を定義すると、layout.tsx で modal という props として受け取ることができます。
こうすることでTOPページから photo/[id] にアクセスした際、URLは変更された状態で @modal を呼び出すことができます。
ルートディレクトリにIntercepting Routesを設ける問題点
しかし、上記の実装では photo/[id] から 他のphoto/[id] に遷移する際にもモーダル表示になってしまうという問題点がありました。
これはInterceptのスコープがルートになっているため全体に影響が及んでしまうのが原因でした。
解決法1 - スコープを分けて他のディレクトリに影響が出ないようにする
一番の解決策はIntercept Routesの影響を一定のディレクトリ内に押さえ込むことです。
app/
├── layout.tsx Root
├── gallery/ ← URL あり(/gallery)
│ ├── layout.tsx ← /gallery にいるときだけスタックに入る
│ └── @modal/
│ └── (..)photo/[id]/page.tsx
└── photo/
└── [id]/page.tsx
上記のように galleryを先ほどのインターセプトが効くように修正をしています。 app/layout.tsx に書いていた内容は gallery内に移動させます。 こうすることでgallery以外では影響が出ないようにすることができます。
このとき @modal の中のインターセプトの書き方が変わってるので注意が必要です。
- (.):現在のセグメントをインターセプト
- (..):1つ上のレベルのセグメントをインターセプト
- (..)(..):2つ上のレベルのセグメントをインターセプト
- (...):appルートからインターセプト
@modal/(..)photo は一つ上のセグメントにある、 photo に遷移する際にインターセプトさせたいので (..) に変更することが必要です。
解決法2 - Hard Navigationを使用する
Intercepting Routes はクライアントナビゲーション(<Link>)で遷移したときにのみ発生します。 そのため、直接アクセスした際や、<a>タグなどによるHard Navigationで遷移させた際は詳細ページがそのまま表示されます。 ただこれはクライアントナビゲーションのメリットを活かせなくなってしまうため注意が必要です。できる限りスコープを分けて管理することが必要です。
まとめ
今回初めて試してみてちゃんと仕様に気づくことができました。
Intercepting Routes を利用する際は「どのスコープでインターセプトを有効にするか」を考え、ディレクトリ設計をすることが大事だと気づきました。
いろいろな記事を調べたのですが、割とインターセプトをルートに設定している記事が多かった印象なので、使うときは気をつけて下さい。
最終的なDEMOはこちらにアップしてます。よければご確認ください!
https://nextjs-parallel-and-intercepting-routes-demo.yskm-dev0818.workers.dev/