副作用管理にuseEffectを利用する理由


### **useEffect の役割**

useEffect は、**「コンポーネントのレンダリング」と「副作用の実行」を分離するためのフック** です。

主に以下の目的で使用されます。

### ** useEffect の目的**

1. **副作用の適切な実行タイミングを制御する**
    - 初回マウント時のみ実行（[] 依存配列）
    - 依存関係の変更時に実行（[dependency]）
    - クリーンアップ処理を適用（return でリソース解放）
2. **不要な副作用の実行を防ぐ**
    - **過剰な再レンダリングを避ける**（依存配列の適切な管理）
    - **不要なデータ取得を抑制**（前回のリクエストをキャンセルするなど）

---

### **副作用とは？**

「**副作用**」とは、**コンポーネントの関数実行（レンダリング）とは直接関係がない処理** を指します。

副作用は、**コンポーネント外の状態を変更する操作** を含むため、**純粋関数では扱えません**。

### ** 副作用の具体例**

- **データ取得（API コール）**
- **イベントリスナーの登録・解除**
- **外部の状態（localStorage / sessionStorage など）を変更**
- **DOM の直接操作**

これらの副作用を適切に管理するために、**useEffect を活用し、必要なタイミングで実行・クリーンアップを行うことが重要** です。


## **なぜ副作用の管理には useEffect が用いられるのか？**

### **① レンダリングを純粋な UI 計算処理として保ち、副作用を分離する**

### **なぜコンポーネントのレンダリングを純粋な UI 計算処理として保つことが重要なのか？**

1. **副作用の実行が必要なタイミングは、レンダリングのタイミングとは必ずしも一致しない**
    - データ取得は、**コンポーネントが描画されるたびに実行する必要はなく、初回マウント時のみで十分なケースが多い**。
    - 例えば、API からデータを取得する場合：
        
        ```jsx
        useEffect(() => {
          fetch("/api/posts")
            .then((res) => res.json())
            .then((data) => setPosts(data));
        }, []); // 空の依存配列を指定することで、初回マウント時のみ実
        ```
        
    - もし useEffect を使わず、レンダリング時に直接データを取得すると、**レンダリングごとに API リクエストが発生し、無駄な負荷がかかる**。
2. **不要な再レンダリングを防ぐ**
    - データ取得の結果を `setState` で保存する場合、その `state` の変更が **再レンダリングを引き起こす**。
    - **もしデータ取得がレンダリングのたびに行われると、無限ループのように再レンダリングが繰り返されてしまう**。
        
        ```jsx
        
        const [posts, setPosts] = useState([]);
        
        // NG: 直接データ取得を行うと、レンダリングのたびに実行される
        const data = fetch("/api/posts").then((res) => res.json());
        setPosts(data);
        
        ```
        
    - useEffect を使えば、依存配列を適切に設定することで **不要な副作用の再実行を防ぐ** ことができる。
    - 

### **② UI の予測可能性を高める**

- **React は「状態 (`state`) と入力 (`props`) に基づいて UI を決定する」という原則を持つ**。
- **副作用が適切に管理されていないと、状態がどのように変化するか予測が難しくなり、デバッグが困難になる**。
- 例えば、**コンポーネントのマウント時に API からデータを取得し、そのデータに基づいて `state` を更新する場合**：
    
    ```jsx
    
    useEffect(() => {
      fetch("/api/posts")
        .then((res) => res.json())
        .then((data) => setPosts(data));
    }, []);
    ```
    
- `useEffect` を使わずにこの処理をコンポーネントの中で直接書いてしまうと、
    - **どのタイミングで API コールが実行されるのか不明確**
    - **データが取得できる前の `state` の状態が分かりづらくなる**
    - **予期せぬ再レンダリングが発生する**
- そのため、`useEffect` に副作用を分離することで、**「このコンポーネントは `state` の変更によって UI を更新するだけ」** というシンプルな構造を保つことができる。

---

### **③ パフォーマンス最適化のため**

- **副作用が適切に管理されないと、レンダリングのたびに不要な処理が実行、関数の再生成が起こり、パフォーマンスが低下する**。
- 特に **API コールやイベントリスナーの登録** などは、無駄に実行されるとアプリのレスポンスが遅くなる。
- `useEffect` を使えば、以下のように **依存配列を適切に設定することで最適なタイミングで実行可能**：
    
    ```jsx
    
    useEffect(() => {
      window.addEventListener("resize", handleResize);
    
      return () => {
        window.removeEventListener("resize", handleResize); // クリーンアップ
      };
    }, []); // 初回マウント時のみ登録
    ```
    
- これにより、**不要なイベントリスナーの登録・解除が防がれ、メモリリークのリスクも回避できる**。


### `useEffect` 内で `setState` を行う場合の React のレンダリングとコミットの流れ（初回マウント時のみ `useEffect` 実行するケース）

1. **初回のレンダリング**
   - コンポーネントが初回レンダリングされ、仮の UI が描画される。
   - **この時点では `useEffect` はまだ実行されない**（レンダリング後に実行されるため）。
   
2. **初回コミット**
   - 初期 UI がブラウザに描画され、DOM に反映される。
   - **ここで `useEffect` が実行される**。
   
3. **`useEffect` 内で `setState` が発生**
   - `useEffect` 内で `setState` を実行すると、**新しい状態が適用され、再レンダリングがトリガーされる**。

4. **再レンダリング**
   - `setState` によって変更された状態を反映し、React がコンポーネントを再レンダリングする。

5. **再コミット**
   - 変更後の UI が DOM に適用される。
   - **`useEffect` は依存配列 `[]` のため再度実行されない**（初回マウント時のみ実行）。

### グローバル状態の更新は副作用に挙げられるか？
　　Yes、グローバル状態の **「更新」** は副作用とみなされる。

#### **理由**
1. **「取得」自体も時に副作用である**
   - グローバル状態（例: Redux / Context API / Zustand など）を取得するだけでは UI の計算に影響を与えない場合が多いが、  
     **「取得時に API からデータをフェッチする」場合は明らかに副作用となる**。
   
2. **「更新」は副作用として管理すべき**
   - `useEffect` を使わずに `setGlobalState` をコンポーネントのレンダリング時に実行すると、  
     **レンダリングのたびに状態が更新され、不要な再レンダリングが発生する可能性がある**。

3. **レンダリングとグローバル状態の更新を同時に行うと「UI の計算結果がブレる」**
   - **状態の変更が「いつ適用されるか」** が不明確になり、**意図しない UI の不整合が発生するリスクがある**。

#### **マウント時にグローバル状態を扱いたいケースでの適切な管理方法**
　**グローバル状態の「取得」** → `useSelector()` や `useContext()` などを使い、レンダリング時に取得  
 　**グローバル状態の「更新」** → `useEffect()` + dispatchや mutation を使って副作用として実行(マウント時にそもそも更新するケースはあまりないかもしれないが、、、)