Next.jsのDynamic Routingを初心者向けに解説

はじめに

Webアプリケーションを開発するとき、ルーティング機能は欠かせないポイントですね。 とくにReactベースのフレームワークであるNext.jsでは、ページ単位でルートを定義できる仕組みが分かりやすいでしょう。 しかし、ユーザーごとに異なるIDを扱いたいときなど、URLパラメータを利用する場面になると「どう実装すればいいのだろう?」と迷うことがあるかもしれません。 そうした疑問にこたえるのが、Next.jsのDynamic Routingと呼ばれる仕組みです。 動的ルーティングを使えば、商品IDやユーザーIDなどをURLに反映し、ページ上で柔軟に扱えるようになります。 今回は、初心者の方にも理解しやすいように、このDynamic Routingの基本から活用例までを丁寧に解説していきます。 実務でも活きる具体例を交えながら進めますので、ぜひ最後まで読んでみてください。

この記事を読むとわかること

  • Dynamic Routingの概要
  • ディレクトリ構造を用いた動的パラメータの設定方法
  • ネストされたルートやCatch-allルーティングの実装ポイント
  • 実務における活用シーンと注意点

動的ルーティングとは?

動的ルーティングとは、ページのURLの一部を変数のように扱い、異なるデータを表示させるための仕組みです。 たとえば、ユーザー一覧ページがあり、そこから個別のユーザープロフィールに遷移させたい場合を考えてみましょう。 URLとしては、/users/1/users/2 のように末尾の数字を変えることで、異なるユーザーの情報を表示できます。 これを実装する際、Next.jsではファイル名やフォルダ名に角カッコを使うことで「この部分を動的に変えますよ」という宣言を行います。 URLのパラメータを取得し、サーバーや外部APIからデータを持ってきてページに反映するのが基本的な流れです。 こうすることで、単一のページファイルを元に様々なURLで異なる情報を扱えるようになります。

多くのWebアプリケーションでは、商品ページや投稿ページなど、多数のエントリを動的に生成しますよね。 そうした場面でDynamic Routingを使えば、複数のルートを個別に用意する手間を省くことができます。 URLとコンテンツを連動させる仕組みが簡単に作れるのは、Next.jsが持つ特徴の一つと言えるでしょう。

Next.jsでの動的ルーティングの基本

Next.jsのプロジェクトでは、pages ディレクトリ内に配置するファイル名やフォルダ名でルーティングが決まります。 たとえば pages/index.js がトップページ、pages/about.js/about というように直接URLに反映されますよね。 これを拡張した形がDynamic Routingで、角カッコを使ってパラメータ部分を表現します。 基本的な流れは次のようになるでしょう。

ページファイルの構造を理解する

まず、pages ディレクトリの中に、動的にルートを設定したい部分を角カッコ付きで命名します。 たとえば pages/users/[id].js というファイルを作成すると、/users/◯◯ の部分がルートパラメータになります。 この[id]の部分が実際のURLで変化する箇所です。 ファイル名が [id].js なので、idというパラメータとしてURLを扱うわけです。

次に、中身の実装では useRouter というフックを利用する方法がよく使われます。 useRouter を使うことで、パラメータを簡単に取得できるのがポイントです。 このフックは next/router からインポートできます。

動的ルーティングの実装手順

実際に pages/users/[id].js 内でパラメータを扱う基本的なコード例は以下のようになります。

import { useRouter } from "next/router";

export default function UserDetailPage() {
  const router = useRouter();
  const { id } = router.query; // URLパラメータを取得

  return (
    <div>
      <h2>ユーザーID: {id}</h2>
      <p>ここにユーザーに関する情報を表示します。</p>
    </div>
  );
}

動的パラメータの定義

上記のように [id].js と命名するだけで、/users/◯◯ というエンドポイントにアクセスした際に、このファイルが呼び出されます。 このとき router.query オブジェクトに、id というキーでURLパラメータが入ってきます。 URLで指定した値によって、表示する情報を切り替えられるわけです。

ページ側でパラメータを受け取る

受け取ったパラメータを使うと、外部APIやデータベースからユーザー情報を取得することが可能です。 実際の実装では、fetchaxios などを使い、ユーザーIDをクエリパラメータとしてリクエストしてデータを取得するでしょう。 取得したデータはコンポーネントの中で表示したり、状態管理を使って保持したりします。 URLの一部をダイレクトに利用するため、複数のユーザー情報に応じて共通のページコンポーネントを再利用しやすい仕組みになっています。

動的ルーティングでは、URLによって異なるデータを取得するために、同じコンポーネントを流用できるというメリットがあります。

ネストされた動的ルーティング

Next.jsでは、ディレクトリ構造を深くすることでネストされたルーティングも簡単に作れます。 たとえば、ユーザーの投稿ページを更に細かく管理したいケースを考えましょう。 /users/1/posts/10 のように、ユーザーIDと投稿IDの両方をURLに含めるような構造が該当します。

ネスト例のディレクトリ構成

pages フォルダの中に users フォルダを作り、その中に [id] フォルダを置きます。 さらに [id] フォルダの下に posts フォルダを作り、最後に [postId].js を配置すると、ネストされた動的ルーティングが実現します。 実際のフォルダ構成例を示します。

pages/
 ┣ index.js
 ┗ users/
[id]/
       ┗ posts/
[postId].js

ここで [id] がユーザーID、[postId] が投稿IDを表す部分ですね。 URLとしては /users/◯◯/posts/□□ といった形でアクセスされ、該当のファイルが読み込まれます。

ネストされたルーティングの実装

たとえば、[postId].js では idpostId の両方がパラメータになるので、router.query.idrouter.query.postId を使って取得します。 コード例を見てみましょう。

import { useRouter } from "next/router";

export default function UserPostPage() {
  const router = useRouter();
  const { id, postId } = router.query;

  return (
    <div>
      <h2>ユーザーID: {id}</h2>
      <h3>投稿ID: {postId}</h3>
      <p>ここに投稿の詳細情報を表示します。</p>
    </div>
  );
}

こういった構成により、「ユーザーIDごとに複数の投稿ページを持つ」ケースを簡単に表現できます。 ディレクトリ構造がそのままURLに反映され、ソースコードを見てもルート設定が直感的に分かりやすいのが特徴です。 複雑なパスを管理するときほど、フォルダの配置で一目瞭然になるため、保守や拡張もしやすいと言えます。

Catch-all ルーティング

ネスト構造とは別に、いくつかのURLパターンを一括で受け取りたい場面があります。 たとえば /docs/anything/else/here のように、階層がいくつ続くか分からないケースです。 そういったときに使えるのがCatch-all ルーティングです。

具体的には、ファイル名を [...params].js のように書きます。 こうすると、/docs/xxx/yyy/zzz といった任意の階層をすべて受け取ることができます。 ただし、想定外のURLまで一括で拾うため、アプリの要件に合うか事前に検討しておく必要があります。

たとえば pages/docs/[...slug].js とした場合、router.query.slug は配列としてすべてのパス要素を受け取ります。 この挙動を活かして、パスの要素をスライスして別々に扱ったり、まとめてキーとして利用したりできます。 自由度が高い半面、通常の静的ルーティングと両立すると複雑化しやすいので、優先度や要件によって整理するといいでしょう。

Catch-all ルーティングを導入する際は、通常のルートや動的ルートとの重複を避けるようにディレクトリ構成を工夫しましょう。

実務でどう活用するか

動的ルーティングを単に学習するだけでなく、実際の業務シーンでどう使うかをイメージしておくと理解が深まるでしょう。 よくある活用例としては、ユーザーごとのダッシュボードや商品ページ、ブログの投稿ページなどが挙げられます。 それぞれのケースで、URL構造が情報の整理に直結するため、ディレクトリ構成を丁寧に設計することが重要です。

データ取得とSEO

商品ページやブログ投稿の詳細画面では、外部APIやデータベースからデータを取ってきて表示しますよね。 このとき、単純なクライアントサイドの取得だけでなく、サーバーサイドの機能を活用するとSEO面でも有利に働く場合があります。 実際には getServerSidePropsgetStaticProps を組み合わせて、サーバーやビルド時に必要なデータを取得・HTMLに反映できます。 これにより、ブラウザや検索エンジンがページを読み込むタイミングで、すでにデータが埋め込まれている状態を作りやすいです。

getServerSideProps / getStaticPropsと組み合わせる

Next.jsにはページコンポーネントとセットで getServerSidePropsgetStaticProps を書くことができます。 動的ルートで取得したURLパラメータを使って、特定のAPIを呼び出してデータを取るのが典型的な例でしょう。 こうすることで、リクエストが来るたびに最新のデータを返したり、ビルド時に静的ファイルを用意して高速化したりできます。 たとえば下記のように、[id].js の中でデータ取得を行うのも一つの方法です。

export async function getServerSideProps(context) {
  const { id } = context.query;
  // idを使ってAPIからデータを取得
  // const res = await fetch(`https://example.com/api/users/${id}`);
  // const data = await res.json();

  return {
    props: {
      userId: id
      // userData: data
    }
  };
}

export default function UserDetail({ userId }) {
  return (
    <div>
      <h1>ユーザーID: {userId}</h1>
      <p>ここにサーバーサイドで取得したデータの内容を表示します。</p>
    </div>
  );
}

サーバーサイドでデータを取得しておけば、クライアント側のレンダリングが完了した時点で情報がすでに表示される状態になります。 動的ルートと組み合わせることで、一つのテンプレートに対して多くのデータを使い回せるので、ページ作成が効率的になるでしょう。

ページ遷移時のポイント

Next.jsではリンクの遷移に next/link がよく使われます。 動的ルーティングでは、リンクを貼るときもパラメータを意識してURLを指定する必要があります。 たとえばユーザー一覧ページからID付きのユーザーページへ遷移させるとき、以下のように書くことができます。

import Link from "next/link";

function UsersList() {
  const dummyUserIds = [1, 2, 3]; // 例として複数のユーザーID

  return (
    <div>
      <h2>ユーザー一覧</h2>
      {dummyUserIds.map((userId) => (
        <div key={userId}>
          <Link href={`/users/${userId}`}>ユーザー {userId} の詳細</Link>
        </div>
      ))}
    </div>
  );
}

export default UsersList;

あらかじめユーザーIDを配列で持っている場合、このようにパス文字列の末尾に ${userId} を付けるだけで遷移先を指定できます。 ネストされたルーティングでも、URLを "/users/"+id+"/posts/"+postId のように繋げて使えばOKです。 遷移が多いアプリを作るときは、ルートの全体像をあらかじめリストアップしておくと、混乱が少なくなります。

エラーを防ぐための注意点

動的ルーティングを行う際は、URLパラメータが不正な値を取る可能性を考える必要があります。 たとえば、存在しないユーザーIDが指定されたり、文字列が入るはずの部分に数値が入ったりといったケースですね。 エラーが発生するとページが正しく表示できなくなる可能性があるので、実務ではサーバーサイドやクライアントサイド両面でバリデーションを行うことが大切です。

また、パラメータの数があっていても、対応するデータが見つからないケースもあるでしょう。 そのようなときには、エラー時のリダイレクトや、404ページへの誘導を行う実装を予め用意しておくと、ユーザビリティが向上します。 Next.jsでは、res.writeHeadnotFound などを使って柔軟にハンドリングできるため、パラメータの取り扱いと合わせて覚えておきたいところです。

まとめ

ここまで、Next.jsのDynamic Routingについて基本的な概要から実装方法、さらに実務レベルでの活用シーンまでを説明してきました。 URLの一部をパラメータとして扱うことで、一つのテンプレートに対して複数のページを柔軟に運用できるのは、大きな利点でしょう。 さらに、ネスト構造やCatch-allルーティングを活用すれば、複雑なパス設定もディレクトリ配置だけでわかりやすく管理できます。 実務で利用する際は、サーバーサイドでのデータ取得やSEO対策と組み合わせるとより効果的です。 初心者の皆さんも、この基本を理解しておけば、応用が必要な場面でもスムーズに対応できるはずです。 ぜひ動的ルーティングを上手く活用して、より使いやすいWebアプリケーションを作ってみてください。

Next.jsをマスターしよう

この記事で学んだNext.jsの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。