🍂

Next.jsのIntercepting Routesを使ってみた

2023/11/13に公開3

こんにちは、hanetsukiです。
今回は、Next.js v13.3のAppRouterで利用できるようになっているIntercepting Routesを使って、モーダルと詳細画面を別々に作成できるようになりました。
本記事では、実際に作成したサイトを元にIntercepting RoutesParallel Routesについてお話しします。

今回作ったもの

Interceptiong RoutesParallel Routesの試験用に、簡単なWebサイトを作成しました。
https://midjourney.tsuki-lab.net/

リポジトリも公開しているので、詳細な実装が気になる方はそちらをご覧ください。
https://github.com/tsuki-lab/next-app-intercepting-routes

主な利用技術

  • Node.js(v18.18.2)
  • Next.js(v14.0.2)
  • React(v18.2.0)

スクリーンショット画面


TOP画面 https://midjourney.tsuki-lab.net/


詳細モーダル


詳細画面 https://midjourney.tsuki-lab.net/image/4w6z707v7l7

Intercepting Routes

そもそもInterceptとはどういう意味でしょうか?
ggrと、下記のような解説がありました。

途中で捕らえる、横取りする、傍受する、さえぎる、迎撃する、要撃する、途中で奪う、インターセプトする、(…を)2 点間にはさみ取る
Weblio辞書より

利用方法・解説

Intercepting Routesを利用する場合は、フォルダの先頭に(..)をつけます。
相対パス../と同じ感覚です。
また、(...)を使用すると appディレクトリからの相対パスとなります。
詳しくは、Intercepting Routes#Conventionをご覧ください。

よくある遷移フローとして、図のようなものがあります。

一覧画面のコンテンツを押下することで、詳細画面へ遷移

この遷移フローを下の図のようにインターセプトします。

本来遷移するはずの詳細画面には到達せず、別のpage.tsxを表示する。

Intercepting Routesは、このように遷移を傍受するような動作をします。

そして、本来遷移したかった詳細画面へは、直リンクで遷移することができます。


直接遷移して詳細画面を表示する

Parallel Routes

今回作成した詳細モーダルを実装するためには、Parallel Routesの履修もしないと行けません。
これも、Next.js 13.3からAppRouterで利用できるようになった機能です。

さて、parallelとはどういう意味でしょうか?
ggrと、下記のような解説がありました。

平行の、(…と)平行して、(事柄など)相等しい、相似する、並行する、(…と)相似して、一致して、対応して、並列の
Weblio辞書より

パラレルワールド(並行世界)とはよく言ったものです。
Parallel Routesはその名の通り、並行するルート挙動を実現させます。

利用方法・解説

Parallel Routes利用する場合は、@modalのようにプレフィックスに@をつけたフォルダを作成することで利用できます。
この@modalより配下がapp/layout.tsx内で参照されるchildrenとは別に、名前付きスロットmodalとして扱えるようになります。


Parallel Routesのイメージ図

app/layout.tsx
export default function Layout(props: {
  children: React.ReactNode
  modal: React.ReactNode
}) {
  return (
    <>
      {props.children}
      {props.modal} {/* 名前付きスロットhogehoge */}
    </>
  )
}


今回は、@modalというルートを作成しました

実装

今回作成したWebサイトでは、下記の要素を満たす必要があります。

  • ページ遷移時にURL付きのモーダルで画像の詳細を開くことができる。(Parallel Routes)
  • 詳細画面はモーダルとは別に存在する。(Intercepting Routes)

そのため、二つの要素を組み合わせる必要あります。
私の環境での実際のファイル構造は下記のようになりました。

トピックとして幾つかのファイルを列挙します。

app/layout.tsx

Parallel Routesの設定を施します。

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

app/@modal/(.)image/[contentId]/page.tsx

詳細モーダルの設定をします。/image/[contentId]のルートをインターセプトし、且つパラレルルートに表示できるように、ファイルのパスを設定します。

app/@modal/(.)image/[contentId]/page.tsx
app/@modal/(.)image/[contentId]/page.tsx
const ImageDetailPage = async () => {
  const data = await fetch(...);
  return (
    <Modal>
      <Image {...data} />
    </Modal>
  );
};

export default ImageDetailPage;

app/@modal/default.tsx

/の時にmodalスロットのパラレルルートが404にならないように設定します。

app/@modal/default.tsx
app/@modal/default.tsx
export default function Default() {
  return null;
}

app/image/[contentId]/page.tsx

/image/[contentId]でリロードした際に設定するための詳細ページを作成します。

app/image/[contentId]/page.tsx
app/image/[contentId]/page.tsx
const ImageDetailPage = async () => {
  const data = await fetch(...);
  return (
    <main>
      <div>
        <div>detail information</div>
        <Image />
      </div>
      <Link href="/">back to top</Link>
    </main>
  );
};

export default ImageDetailPage;

おわりに

今回はIntercepting RoutesParallel Routesを使った実装をしてみました。
実際に作成してみて・触ってみて思った点が2点。

  • ユーザーのページ回遊を妨げないUXを作成できる
  • インターセプト状態と通常ページとで同等機能を用意する必要がある(?)

ECの商品ページやサービスのログイン・サインインページなどで活きそうだなと感じました。
ニーズが合いそうな機会があったら提案してみたいものですね!

それでは今回はこれにて。

参考

https://github.com/vercel-labs/nextgram
https://azukiazusa.dev/blog/nextjs-interception-routes/
https://nextjs.org/docs/app/building-your-application/routing/intercepting-routes
https://nextjs.org/docs/app/building-your-application/routing/parallel-routes
https://github.com/tsuki-lab/next-app-intercepting-routes

chot Inc. tech blog

Discussion

ninonino

tree-to-image 使ってくれている!ありがとうございます🙌

デモサイト綺麗ですね!
(Next.js 14 の不安定さ起因な気がしますが初回ルートアクセス時、不規則にクラッシュしてるかもです(Safari, iOS, Mac))

余談ですが挿絵は Figma でしょうか?(矢印など綺麗だったので...)
https://storage.googleapis.com/zenn-user-upload/0db8d337e858-20231112.png

hanetsukihanetsuki

tree-to-image 大変心地よく利用させていただきました!
(クラッシュ報告ありがとうございます。なかなか安定してくれないですね...少し様子見しておきたいと思います)

余談ですが挿絵は Figma でしょうか?

こちらはFigJamを利用しています!
Figmaでも良いのですが、カードや矢印をプリセットで扱えるので図示する際には非常に便利ですー

ninonino

FigJam ありがとうございます!使ってみます! 🙌