# 機能設計書 52-next/navigation

## 概要

本ドキュメントは、Next.jsの`next/navigation`モジュールの機能設計を記述する。App Router用のナビゲーションフック群（useRouter、usePathname、useSearchParams、useParams、useSelectedLayoutSegment、useSelectedLayoutSegments）を提供し、クライアントコンポーネントからのプログラマティックナビゲーションとルート情報の取得を可能にする。

### 本機能の処理概要

**業務上の目的・背景**：App Routerではファイルシステムベースのルーティングが行われるが、アプリケーション内でプログラマティックにルート情報を取得したりナビゲーションを制御する必要がある。`next/navigation`モジュールは、React ContextとHooksパターンを通じて、クライアントコンポーネントから現在のURL情報やルーターインスタンスにアクセスするための標準的なAPIを提供する。

**機能の利用シーン**：検索フォームでのクエリパラメータ取得（useSearchParams）、現在のパス名に基づくアクティブナビゲーションの表示（usePathname）、フォーム送信後のプログラマティックナビゲーション（useRouter）、動的ルートパラメータの取得（useParams）、レイアウト内でのアクティブセグメント表示（useSelectedLayoutSegment）など。

**主要な処理内容**：
1. useRouter: App Routerインスタンスの取得（push, replace, refresh, prefetch, back, forward）
2. usePathname: 現在のURLパス名の取得
3. useSearchParams: 現在のURLクエリパラメータの読み取り専用アクセス
4. useParams: 動的ルートパラメータの取得
5. useSelectedLayoutSegment: 現在レイアウトの直下アクティブセグメントの取得
6. useSelectedLayoutSegments: 現在レイアウト配下の全アクティブセグメントパスの取得
7. redirect / permanentRedirect / notFound / forbidden / unauthorized の再エクスポート

**関連システム・外部連携**：App Routerの内部コンテキスト（AppRouterContext、LayoutRouterContext、SearchParamsContext、PathnameContext、PathParamsContext）と連携。サーバーサイドではdynamic renderingのトラッキングとも統合される。

**権限による制御**：各フック自体に権限制御はないが、unauthorizedやforbidden関数を通じてアクセス制御を実現できる。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 全画面で利用可能な汎用ナビゲーションフック群 |

## 機能種別

ナビゲーション / React Hooks API

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| parallelRouteKey (useSelectedLayoutSegment/useSelectedLayoutSegments) | string | No | 並列ルートキー（デフォルト: 'children'） | 文字列型 |

### 入力データソース

- React Context（AppRouterContext, SearchParamsContext, PathnameContext, PathParamsContext, LayoutRouterContext, NavigationPromisesContext）
- サーバーサイドでは`useDynamicRouteParams`/`useDynamicSearchParams`によるdynamic rendering追跡

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| AppRouterInstance (useRouter) | AppRouterInstance | push, replace, refresh, prefetch, back, forwardメソッドを持つルーターオブジェクト |
| pathname (usePathname) | string | 現在のURLパス名 |
| searchParams (useSearchParams) | ReadonlyURLSearchParams | 読み取り専用のURLSearchParamsオブジェクト |
| params (useParams) | Params | 動的ルートパラメータのオブジェクト |
| segment (useSelectedLayoutSegment) | string \| null | 直下のアクティブセグメント名 |
| segments (useSelectedLayoutSegments) | string[] | 配下の全アクティブセグメントパス配列 |

### 出力先

- Reactコンポーネントの戻り値として利用される

## 処理フロー

### 処理シーケンス

```
1. useRouter()
   └─ AppRouterContext から AppRouterInstance を取得
2. usePathname()
   ├─ サーバーサイド: useDynamicRouteParams で動的レンダリング追跡
   └─ PathnameContext から現在のパス名を取得
3. useSearchParams()
   ├─ サーバーサイド: useDynamicSearchParams で動的レンダリング追跡
   └─ SearchParamsContext から ReadonlyURLSearchParams を生成
4. useParams()
   ├─ サーバーサイド: useDynamicRouteParams で動的レンダリング追跡
   └─ PathParamsContext からパラメータオブジェクトを取得
5. useSelectedLayoutSegment()
   ├─ useSelectedLayoutSegments() を内部で呼び出し
   └─ computeSelectedLayoutSegment() で直下セグメントを算出
6. useSelectedLayoutSegments()
   └─ LayoutRouterContext.parentTree から全セグメントパスを取得
```

### フローチャート

```mermaid
flowchart TD
    A[クライアントコンポーネント] --> B{使用するフック}
    B -->|useRouter| C[AppRouterContext]
    B -->|usePathname| D[PathnameContext]
    B -->|useSearchParams| E[SearchParamsContext]
    B -->|useParams| F[PathParamsContext]
    B -->|useSelectedLayoutSegment| G[LayoutRouterContext]
    C --> H[AppRouterInstance]
    D --> I[pathname: string]
    E --> J[ReadonlyURLSearchParams]
    F --> K[Params object]
    G --> L[getSelectedLayoutSegmentPath]
    L --> M[segment/segments]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | ルーターマウント必須 | useRouterはAppRouterContextがnullの場合にエラーをスローする | App Routerがマウントされていない場合 |
| BR-52-02 | 動的レンダリング追跡 | サーバーサイドでのuseSearchParams/useParams/usePathname呼び出しはdynamic rendering追跡を実行 | typeof window === 'undefined'の場合 |
| BR-52-03 | ReadonlyURLSearchParams | useSearchParamsの戻り値は読み取り専用のURLSearchParams | 常時 |
| BR-52-04 | Suspense DevTools連携 | 開発モードではNavigationPromisesContextを通じてSuspense DevToolsと連携 | NODE_ENV !== 'production' |

### 計算ロジック

- `computeSelectedLayoutSegment`: `useSelectedLayoutSegments`の結果から最初のセグメント、または`__PAGE__`キーの場合はnullを返す
- `getSelectedLayoutSegmentPath`: FlightRouterStateのparentTreeから指定parallelRouteKeyに対応するセグメントパスを再帰的に取得

## データベース操作仕様

該当なし（クライアントサイドフックのため）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | invariantエラー | useRouterがApp Router外で使用された | 'invariant expected app router to be mounted'エラーをスロー |
| - | null戻り値 | Pages RouterでuseSearchParamsが使用された | nullが返される（next-env.d.tsの型オーバーロードで対応） |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- useSearchParamsはuseMemoで ReadonlyURLSearchParamsインスタンスをメモ化
- 各フックはReact Contextの変更のみで再レンダリングが発生する軽量な設計

## セキュリティ考慮事項

- ReadonlyURLSearchParamsにより、searchParamsの意図しない変更を防止
- サーバーサイドでの動的レンダリング追跡により、静的/動的レンダリングの適切な判定を保証

## 備考

- `next/navigation`は`redirect`, `permanentRedirect`, `notFound`, `forbidden`, `unauthorized`, `unstable_rethrow`, `RedirectType`も再エクスポートしている
- `unstable_isUnrecognizedActionError`もエクスポートされている
- Pages Routerでは`next/router`を使用する必要がある

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | app-router-context.shared-runtime.ts | `packages/next/src/shared/lib/app-router-context.shared-runtime.ts` | AppRouterInstance型定義 - push, replace, refresh, prefetch, back, forward |
| 1-2 | hooks-client-context.shared-runtime.ts | `packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts` | SearchParamsContext, PathnameContext, PathParamsContext, NavigationPromisesContext |

**読解のコツ**: 各フックは対応するReact Contextから値を取得するシンプルなラッパーであるが、サーバーサイドでの動的レンダリング追跡ロジックが条件付きで追加されている点に注意。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | navigation.ts | `packages/next/src/api/navigation.ts` | `export * from '../client/components/navigation'` - 単純な再エクスポート |
| 2-2 | navigation.ts | `packages/next/src/client/components/navigation.ts` | **全フックの実装** - useSearchParams, usePathname, useRouter, useParams等 |

**主要処理フロー**:
1. **56-83行目**: useSearchParams - SearchParamsContextからReadonlyURLSearchParamsを生成
2. **103-119行目**: usePathname - PathnameContextから文字列パスを取得
3. **146-153行目**: useRouter - AppRouterContextからルーターインスタンスを取得
4. **173-187行目**: useParams - PathParamsContextからパラメータオブジェクトを取得
5. **215-239行目**: useSelectedLayoutSegments - LayoutRouterContext.parentTreeからセグメントパスを取得
6. **260-283行目**: useSelectedLayoutSegment - 直下セグメントの取得

#### Step 3: サーバーサイド動的レンダリング追跡を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | navigation.ts | `packages/next/src/client/components/navigation.ts` | **21-33行目**: useDynamicRouteParams/useDynamicSearchParams - サーバーサイド専用の動的require |

#### Step 4: 再エクスポートを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | navigation.react-server.ts | `packages/next/src/client/components/navigation.react-server.ts` | redirect, permanentRedirect, notFound等のReact Server Component向けエクスポート |

### プログラム呼び出し階層図

```
next/navigation (api/navigation.ts)
    |
    +-- client/components/navigation.ts
         |
         +-- useSearchParams()
         |       +-- useDynamicSearchParams() [server only]
         |       +-- useContext(SearchParamsContext)
         |       +-- new ReadonlyURLSearchParams()
         |
         +-- usePathname()
         |       +-- useDynamicRouteParams() [server only]
         |       +-- useContext(PathnameContext)
         |
         +-- useRouter()
         |       +-- useContext(AppRouterContext)
         |
         +-- useParams()
         |       +-- useDynamicRouteParams() [server only]
         |       +-- useContext(PathParamsContext)
         |
         +-- useSelectedLayoutSegments()
         |       +-- useDynamicRouteParams() [server only]
         |       +-- useContext(LayoutRouterContext)
         |       +-- getSelectedLayoutSegmentPath()
         |
         +-- useSelectedLayoutSegment()
                 +-- useSelectedLayoutSegments()
                 +-- computeSelectedLayoutSegment()
```

### データフロー図

```
[入力]                          [処理]                       [出力]

AppRouterContext -----------> useRouter() --------------> AppRouterInstance
PathnameContext -----------> usePathname() -------------> string
SearchParamsContext --------> useSearchParams() ---------> ReadonlyURLSearchParams
PathParamsContext ----------> useParams() ----------------> Params
LayoutRouterContext --------> useSelectedLayoutSegment() -> string | null
LayoutRouterContext --------> useSelectedLayoutSegments() -> string[]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| navigation.ts (api) | `packages/next/src/api/navigation.ts` | ソース | エントリーポイント（再エクスポート） |
| navigation.ts (components) | `packages/next/src/client/components/navigation.ts` | ソース | フック実装本体（302行） |
| navigation.react-server.ts | `packages/next/src/client/components/navigation.react-server.ts` | ソース | RSC向けエクスポート |
| app-router-context.shared-runtime.ts | `packages/next/src/shared/lib/app-router-context.shared-runtime.ts` | ソース | AppRouterContext定義 |
| hooks-client-context.shared-runtime.ts | `packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts` | ソース | 各種Context定義 |
| segment.ts | `packages/next/src/shared/lib/segment.ts` | ソース | セグメント計算ユーティリティ |
| dynamic-rendering.ts | `packages/next/src/server/app-render/dynamic-rendering.ts` | ソース | 動的レンダリング追跡 |
