🙆

App RouterとPage Routerのルーティング差分まとめ

2024/11/27に公開

本記事の目的

2023 年ごろ Next.js13 が発表され、従来のルーティング機能 Page Router と別に、App Router が追加されました。公式は App Router の使用を推奨していますし、発表から 1 年以上経っていて徐々に記事も増えてきたので、流石に App Router 採用に踏み切って良いと思います。

しかし、App Router はこれまでの React や Page Router による書き方と大きく異なります。これは、React Server Components(RSC) というアーキテクチャが導入され、開発の考え方が大きく変化したからです。

この記事では、Next.js 定義から Page Router と App Router の差分、ルーティングの意義について説明していきたいと思います。

Next.js とは

Next.js は、React の機能を拡張した強力なウェブ開発フレームワーク。

React は主にユーザーインターフェース(UI)の構築に特化した JavaScript ライブラリですが、Next.js は React の機能を基盤としつつ、より包括的な開発環境を提供しています。

大きな特徴として、レンダリング(ブラウザ上で UI を生成し表示する一連の処理)の方式が、SSR や SSG など、柔軟に選択できるということです。これによって、SEO 対策や、読み込み速度などのパフォーマンス向上に繋がるという利点があります。

また、Node.js と名前が似ているから、仲間かと思われるかもしれませんが、Node.js はサーバーサイドの JavaScript 実行環境であり、Next.js は Node.js 上で動作するフレームワークです。

App Router の意義

web アプリを開発する上で、異なるページや機能間のナビゲーション(移動)を設定する必要が出てきます。これをルーティングと言います。React+Vite のような構成で web アプリを作る場合は、React 自体にルーティング機能が内蔵されていないため、ルーティングを実現するために React Router などのサードパーティライブラリを使用する必要があります。これは Vue.js でも同様で、設定がやや複雑でめんどいです。

Next.js ではこのルーティングを感覚的に行うことのできる機能が備わっています。従来の Page Router と新しく追加された App Router です。どちらもディレクトリ構造でルーティングをサポートする点は同じですが、App Router は Page Router よりも複雑なルーティング設定が可能になりました。

App Router と Page Router の違い

Page Router でも使えた従来の機能は、App Router で以下のように変化しました。

Page Router

/pages
  ├── index.js           // `/`
  ├── about.js           // `/about`
  ├── blog/
  │   ├── index.js       // `/blog`
  │   ├── [...slug].js   // `/docs/*` に対応
  │   └── [id].js        // `/blog/:id`
  ├── _app.js            // 全体の共通ロジック。レイアウトとか
  ├── _document.js       // HTMLのカスタマイズ
  ├── api/
  │   └── hello.js       // `/api/hello`

App Router

/app
  ├── layout.js          // 全体のレイアウト
  ├── page.js            // `/`
  ├── about/
  │   └── page.js        // `/about`
  ├── blog/
  │   ├── layout.js      // `/blog` 以下の共通レイアウト
  │   ├── page.js        // `/blog`
  │   ├── [...slug]/
  │   │   └── page.js    // `/docs/*`
  │   └── [id]/
  │       └── page.js    // `/blog/:id`
  ├── api/
      └── hello/route.js // `/api/hello`

 
 

さらに App Router にはこれに加えて、次の 4 項目が追加されました。

1. オプショナルキャッチオール([[...param]]

/app
  ├── search/
  │   ├── [[...filters]]/
  │       └── page.js          // `/search` または `/search/*` (検索ページ)
    • /search
    • /search/category/react
  • 必須ではないパラメータに対応する際に便利

2. セグメントグループ((segment)

/app
  ├── (auth)/
  │   ├── login/
  │   │   └── page.js          // `/login` (ログインページ)
  │   ├── register/
  │       └── page.js          // `/register` (新規登録ページ)
  ├── (marketing)/
  │   ├── home/
  │   │   └── page.js          // `/home` (マーケティングホーム)
  │   ├── pricing/
  │       └── page.js          // `/pricing` (価格情報ページ)
  • (auth)(marketing) は URL に含まれない。グループ化したいけど、URL には干渉したくないなという時に便利

3. パラレルルーティング(@parallel

/app
  ├── dashboard/
  │   ├── layout.js
  │   ├── @analytics/
  │   │   └── page.js  // `/dashboard` の一部に含まれる
  │   ├── @settings/
  │       └── page.js  // `/dashboard` の一部に含まれる
  • layout.js内で受け取る特定のキー(例: @analytics@settings)によって、それぞれのルートがレンダリングされる

  • layout.jsが以下のようなコードの場合、

    import { useSearchParams } from "next/navigation";
    
    export default function DashboardLayout({ analytics, settings, children }) {
      const searchParams = useSearchParams();
      const view = searchParams.get("view");
    
      return (
        <div>
          <nav>
            <ul>
              <li><a href="/dashboard">Overview</a></li>
              <li><a href="/dashboard?view=analytics">Analytics</a></li>
              <li><a href="/dashboard?view=settings">Settings</a></li>
            </ul>
          </nav>
    
          <main>
            {view === "analytics" && analytics}
            {view === "settings" && settings}
            {!view && children}
          </main>
        </div>
      );
    }
    
    • /dashboard: layout.jspage.js がレンダリングされる(デフォルトビュー)
    • /dashboard?view=analytics: layout.js 内で @analytics/page.js がレンダリングされる
    • /dashboard?view=settings: layout.js 内で @settings/page.js がレンダリングされる
  • 同じエンドポイントで複数のビューを実現したいときに便利

4. 特殊ファイル

/app
  ├── error.js                 // エラーページ (全体で共有)
  ├── loading.js               // ローディング表示 (全体で共有)
  ├── not-found.js             // 404エラーページ (全体で共有)
  ├── dashboard/
  │   ├── layout.js            // `/dashboard` (共通レイアウト)
  │   ├── page.js              // `/dashboard`
  │   ├── error.js             // `/dashboard`専用のエラーページ
  │   ├── loading.js           // `/dashboard`専用のローディング表示
  │   ├── analytics/
  │   │   └── page.js          // `/dashboard/analytics` (アナリティクスページ)

まとめ

以上をまとめると、App Router でできるルーティングの全容は以下の通り。

/app
  ├── page.js                  // `/` (ホームページ)
  ├── about/
  │   └── page.js              // `/about`
  ├── blog/
  │   ├── page.js              // `/blog`
  │   ├── [id]/
  │   │   └── page.js          // `/blog/:id`
  │   └── [id]/
  │       └── edit/
  │           └── page.js      // `/blog/:id/edit`
  ├── dashboard/
  │   ├── layout.js            // `/dashboard` (共通レイアウト)
  │   ├── page.js              // `/dashboard`
  │   ├── error.js             // `/dashboard`専用のエラーページ
  │   ├── loading.js           // `/dashboard`専用のローディング表示
  │
  ├── docs/
  │   ├── page.js              // `/docs`
  │   ├── [...slug]/
  │       └── page.js          // `/docs/*`
  ├── search/
  │   ├── [[...filters]]/
  │       └── page.js          // `/search` または `/search/*`
  ├── (auth)/
  │   ├── login/
  │   │   └── page.js          // `/login`
  │   ├── register/
  │       └── page.js          // `/register`
  ├── (marketing)/
  │   ├── home/
  │   │   └── page.js          // `/home`
  │   ├── pricing/
  │       └── page.js          // `/pricing`
  ├── error.js                 // エラーページ (全体で共有)
  ├── loading.js               // ローディング表示 (全体で共有)
  ├── not-found.js             // 404エラーページ (全体で共有)
  ├── dashboard/
  │   ├── layout.js            // `/dashboard` (共通レイアウト)
  │   ├── error.js             // `/dashboard`専用のエラーページ
  │   ├── loading.js           // `/dashboard`専用のローディング表示
  │   ├── page.js              // `/dashboard`
  │   ├── @analytics/
  │   │   └── page.js          // `/dashboard`のアナリティクスビュー
  │   ├── @settings/
  │       └── page.js          // `/dashboard`の設定ビュー

これにより、

  • 開発者目線 → どのファイルがどこにあるのか直感的でわかりやすい!
  • 利用者目線 →url が直感的でわかりやすい!

と双方良しになるという寸法です。

 
 
 
 
以上です。

Discussion