# 機能設計書 6-effect()

## 概要

本ドキュメントは、Vue 3のリアクティビティシステムにおける`effect()` APIの機能設計を記述する。`effect()`は副作用関数の依存性を自動追跡し、依存データの変更時に自動再実行を行う低レベルAPIである。

### 本機能の処理概要

`effect()`は、副作用関数をReactiveEffectインスタンスでラップし、関数内でアクセスしたリアクティブデータを自動的に依存関係として記録する。依存データが変更されると副作用関数が自動的に再実行される。ReactiveEffectクラスはVueのリアクティビティシステムの中核であり、watch/watchEffect/computed/レンダリングの全てがこのクラスを基盤として動作する。

**業務上の目的・背景**：computed()やwatch()の内部基盤として機能する低レベルAPIであり、カスタムリアクティビティ動作を実装するために公開されている。通常のアプリケーション開発ではwatch/watchEffectの使用が推奨されるが、ライブラリ開発者やフレームワーク拡張者向けにより細かな制御を提供する。

**機能の利用シーン**：カスタムリアクティビティ統合、テスト用のリアクティブ副作用、パフォーマンスクリティカルなリアクティブ処理の最適化などに使用される。

**主要な処理内容**：
1. ReactiveEffectインスタンスの生成（副作用関数をラップ）
2. 即時実行（初回run()）により依存性を自動収集
3. Subscriberインターフェースによる依存Depからの変更通知受信
4. schedulerオプションによるカスタム実行スケジューリング
5. stop()による明示的な停止とクリーンアップ
6. pause()/resume()によるエフェクトの一時停止・再開

**関連システム・外部連携**：`@vue/reactivity`パッケージに所属。Dep/Linkベースの依存性追跡システム、EffectScope（スコープ管理）と連携する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面機能マッピングにeffect()単体の関連画面は登録されていない（内部APIとして使用） |

## 機能種別

リアクティビティ管理 / 低レベル副作用API

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| fn | () => T | Yes | 副作用関数。内部でアクセスしたリアクティブデータが依存として追跡される | 関数であること |
| options | ReactiveEffectOptions | No | scheduler, allowRecurse, onStop, onTrack, onTrigger | - |

### 入力データソース

APIの引数として直接渡される関数とオプション。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| runner | ReactiveEffectRunner\<T\> | 手動で副作用を再実行可能なランナー関数。`.effect`プロパティでReactiveEffectインスタンスにアクセス可能 |

### 出力先

呼び出し元に返却。

## 処理フロー

### 処理シーケンス

```
1. effect(fn, options?)が呼び出される
2. fnが既にRunnerの場合、元のfnを取得
3. new ReactiveEffect(fn)を生成
   └─ activeEffectScopeが存在すればeffects配列に登録
4. optionsがあればextend(e, options)でプロパティをコピー
5. e.run()で初回実行
   ├─ cleanupEffect(e) - 前回クリーンアップ
   ├─ prepareDeps(e) - 依存リンクのversion=-1に初期化
   ├─ activeSub = this - 現在のアクティブSubscriberを設定
   ├─ fn() - 副作用関数実行（この間のリアクティブアクセスが依存として記録）
   └─ cleanupDeps(e) - 未使用依存の削除
6. runner = e.run.bind(e)を生成
7. runner.effect = eを設定
8. runnerを返却
```

### フローチャート

```mermaid
flowchart TD
    A[effect fn, options] --> B{fnがRunner?}
    B -->|Yes| C[fn = fn.effect.fn]
    B -->|No| D[new ReactiveEffect fn]
    C --> D
    D --> E{options?}
    E -->|Yes| F[extend e, options]
    E -->|No| G[e.run 初回実行]
    F --> G
    G --> H{エラー?}
    H -->|Yes| I[e.stop, throw err]
    H -->|No| J[runner = e.run.bind e]
    J --> K[runner.effect = e]
    K --> L[runner返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | 自動依存追跡 | run()実行中のリアクティブデータアクセスが依存として記録される | 常時 |
| BR-02 | 自動再実行 | 依存データ変更時にtrigger()経由で自動的にrunIfDirty()が呼ばれる | schedulerが未設定の場合 |
| BR-03 | スケジューラ | schedulerオプションで再実行のタイミングをカスタマイズ可能 | scheduler設定時 |
| BR-04 | 依存クリーンアップ | run()毎に前回の依存リストと比較し、未使用の依存を削除する | run()実行後 |
| BR-05 | EffectScope統合 | 生成時にactiveEffectScopeが存在すれば自動的にスコープに登録 | activeEffectScope存在時 |
| BR-06 | 一時停止・再開 | pause()で一時停止、resume()で再開可能。停止中の変更は再開時に適用 | pause()/resume()呼び出し時 |

### 計算ロジック

- EffectFlagsによるビットマスク管理: ACTIVE(1), RUNNING(2), TRACKING(4), NOTIFIED(8), DIRTY(16), ALLOW_RECURSE(32), PAUSED(64), EVALUATED(128)

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ランタイムエラー | 初回run()でfn内部でエラー発生 | e.stop()で停止後、エラーを再throw |
| - | 開発者警告 | onEffectCleanup()がアクティブエフェクト外で呼ばれた場合 | 警告メッセージを出力 |
| - | 内部警告 | activeSub復元の不整合 | `Active effect was not restored correctly` |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 双方向リンクリスト（Link）による効率的な依存管理。O(1)での追加・削除
- batch処理による複数依存変更の一括処理
- isDirty()による遅延評価（変更がない場合は再実行をスキップ）

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

特になし

## 備考

- `stop(runner)`で明示的に停止可能
- `pauseTracking()`/`enableTracking()`/`resetTracking()`で依存追跡を一時的に制御可能
- `onEffectCleanup(fn)`で副作用のクリーンアップ関数を登録可能
- ReactiveEffectクラスはwatch, watchEffect, computedの全ての基盤

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | effect.ts | `packages/reactivity/src/effect.ts` | EffectFlags列挙型（41-53行目）。ビットフラグによる状態管理 |
| 1-2 | effect.ts | `packages/reactivity/src/effect.ts` | Subscriberインターフェース（58-83行目）。deps/depsTail/flags/next/notify() |
| 1-3 | effect.ts | `packages/reactivity/src/effect.ts` | ReactiveEffectOptions, ReactiveEffectRunner型定義（28-37行目） |

**読解のコツ**: ReactiveEffectはSubscriberインターフェースを実装し、Depからの通知を受け取る。deps/depsTailは双方向リンクリストのHead/Tailポインタであり、このエフェクトが依存する全てのDepへのリンクを管理する。

#### Step 2: ReactiveEffectクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | effect.ts | `packages/reactivity/src/effect.ts` | ReactiveEffectクラス（87-217行目）。コンストラクタ、run()、stop()、trigger() |

**主要処理フロー**:
- **116-119行目**: コンストラクタ。activeEffectScopeへの自動登録
- **151-181行目**: run()。cleanupEffect -> prepareDeps -> activeSub設定 -> fn() -> cleanupDeps
- **183-193行目**: stop()。全依存の購読解除、クリーンアップ実行
- **195-203行目**: trigger()。PAUSED/scheduler/runIfDirtyの分岐

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | effect.ts | `packages/reactivity/src/effect.ts` | effect()関数（473-494行目）。ReactiveEffect生成と初回実行 |

**主要処理フロー**:
1. **477-479行目**: 既存Runnerの場合、元のfnを取得
2. **481行目**: `new ReactiveEffect(fn)`
3. **482-484行目**: optionsの適用
4. **486行目**: `e.run()`で初回実行
5. **491-493行目**: runnerの生成とeffectプロパティの設定

#### Step 4: batch処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | effect.ts | `packages/reactivity/src/effect.ts` | batch()、startBatch()、endBatch()（240-299行目）。バッチ処理によるエフェクト実行 |

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

```
effect(fn, options?)
    |
    +-- new ReactiveEffect(fn)
    |       +-- activeEffectScope.effects.push(this)  // スコープ登録
    |
    +-- extend(e, options)     // scheduler等のオプション適用
    |
    +-- e.run()                // 初回実行
    |       +-- cleanupEffect(e)       // 前回クリーンアップ
    |       +-- prepareDeps(e)         // 依存version=-1初期化
    |       +-- activeSub = this       // アクティブSubscriber設定
    |       +-- fn()                   // 副作用関数実行
    |       |       +-- [リアクティブアクセス]
    |       |               +-- dep.track()    // 依存記録
    |       +-- cleanupDeps(e)         // 未使用依存削除
    |       +-- activeSub = prevEffect // 復元
    |
    +-- runner = e.run.bind(e)
    +-- runner.effect = e
    +-- return runner

[依存変更時]
Dep.trigger() -> Dep.notify() -> e.notify() -> batch(e)
    -> endBatch() -> e.trigger() -> e.runIfDirty() -> e.run()
```

### データフロー図

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

fn: () => T    ───>  effect(fn)                  ───>  ReactiveEffectRunner
                         |
                    ReactiveEffect生成
                         |
                    初回run()実行
                         |
                    fn()内のリアクティブアクセス
                         |
                    dep.track()で依存記録
                         |
                    [依存変更時]
                         |
                    dep.trigger() -> notify()
                         |
                    batch() -> endBatch()
                         |
                    e.trigger() -> runIfDirty()
                         |
                    fn()再実行
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| effect.ts | `packages/reactivity/src/effect.ts` | ソース | effect()のメイン実装。ReactiveEffectクラス、batch処理、shouldTrack管理 |
| dep.ts | `packages/reactivity/src/dep.ts` | ソース | Dep/Linkクラス。依存性追跡とトリガーの中核 |
| effectScope.ts | `packages/reactivity/src/effectScope.ts` | ソース | EffectScope。エフェクトのグループ管理 |
| index.ts | `packages/reactivity/src/index.ts` | ソース | パッケージエクスポート定義 |
