next/router と next/navigation の違い
問題の説明
Next.jsではnext/router
とnext/navigation
の両パッケージにuseRouter()
フックが存在しますが、返されるオブジェクトが異なります。なぜ同じフック名でありながら、2つの異なるルーティングパッケージが存在するのでしょうか?この違いを理解しないと、以下のエラーが発生する可能性があります:
Error: NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted
この問題の核心は、Next.js 13で導入された新しいルーティングシステム「App Router」と、従来の「Pages Router」のアーキテクチャの違いにあります。
根本的な違い
next/router
(Pages Router向け)
- 使用場所:
/pages
ディレクトリ構造のプロジェクト - 目的: クライアントサイドナビゲーションを主体とした従来型ルーティング
- 特徴:
- Next.js v12以前から存在するレガシーシステム
- クライアントコンポーネントに特化
- 比較的単純なルーティングニーズに対応
next/navigation
(App Router向け)
- 使用場所:
/app
ディレクトリ構造のプロジェクト (Next.js v13以上) - 目的: サーバーサイドレンダリングを完全サポートした最新ルーティング
- 特徴:
useRouter
,redirect
,notFound
などの関数を提供- サーバーコンポーネントとクライアントコンポーネントの両方をサポート
- 自動コード分割や高度なレイアウト管理を実現
Next.jsのプロジェクト構造
Next.jsは2つのルーティングモードを並行サポート:
/pages
ディレクトリ → Pages Router (next/router
)/app
ディレクトリ → App Router (next/navigation
)
実際の使い分け
Pages Router の場合 (pages/
ディレクトリ)
// pages/home.js
import { useRouter } from 'next/router';
export default function HomePage() {
const router = useRouter();
const handleClick = () => {
router.push('/about'); // ページ遷移
};
return (
<button onClick={handleClick}>
Aboutページへ移動
</button>
);
}
App Router の場合 (app/
ディレクトリ)
// app/home/page.js
'use client'; // クライアントコンポーネント指定
import { useRouter } from 'next/navigation';
export default function HomePage() {
const router = useRouter();
const handleClick = () => {
router.push('/about'); // ページ遷移
};
return (
<button onClick={handleClick}>
Aboutページへ移動
</button>
);
}
重要
App Router プロジェクトでnext/router
を使用すると、致命的なエラーが発生:
Error: NextRouter was not mounted.
公式ドキュメントで解決法を確認:
https://nextjs.org/docs/messages/next-router-not-mounted
主な機能比較
機能 | next/router (Pages Router) | next/navigation (App Router) |
---|---|---|
データ取得 | getServerSideProps など | サーバーコンポーネント内で直接実装 |
エラー処理 | カスタムErrorページ | notFound() 関数で動的制御可能 |
リダイレクト | クライアントサイド限定 | サーバーサイドでのリダイレクト対応 |
ルーティング | 基本ナビゲーション機能 | 高度な並行ルーティング機能搭載 |
将来性 | 新機能追加未定 | 最新機能の優先実装対象 |
移行ガイド
Pages RouterからApp Routerに移行する場合:
next/router
→next/navigation
にインポート元を変更/pages
ディレクトリのファイルを/app
構造に変換getServerSideProps
などのデータ取得方法をサーバーコンポーネントパターンに移行- 動的ルーティングパラメータの取得方法を
router.query
→params
オブジェクトに変更
// app/blog/[slug]/page.js
export default function BlogPage({ params }) {
const { slug } = params; // URLパラメータ直接取得
return <h1>{slug}の記事</h1>;
}
ベストプラクティス
- 新規プロジェクトでは常にApp Routerを採用:
/app
ディレクトリ構成で開始しnext/navigation
を使用 - 既存プロジェクト: Pages Routerが機能している場合作成しない
- 混在時の注意: 同一プロジェクトで両方使用可能が、コード管理が複雑化
- サーバーコンポーネント:
next/navigation
使用時にサーバーサイド処理を最大限活用可能
// app/admin/page.js
import { redirect } from 'next/navigation';
export default async function AdminPage() {
const user = await getCurrentUser();
if (!user.isAdmin) {
redirect('/login'); // サーバー側でリダイレクト
}
return <AdminDashboard />;
}
結論
next/router
と next/navigation
の選択はプロジェクト構造で決定:
/pages
ディレクトリを使用 →next/router
/app
ディレクトリを使用 (Next.js v13以降) →next/navigation
App RouterはReact 18のサーバーコンポーネント機能を基盤とし、パフォーマンス最適化や高度なルーティング制御が可能です。新しいプロジェクトはApp Routerを採用し、next/navigation
を利用することで、Next.jsの最新機能を最大限活用できます。