useReducerの仕様を噛み砕いて理解する

「useReducerについて理解を深めたい！」
「いまいちピンとこない！」
「でぃすぱっち？難しそう！」

という方に...
私なりに噛み砕いてアウトプットしてみます。([useReducerの公式リファレンス](https://ja.react.dev/reference/react/useReducer))

## useReducerの使い方

他のhooksと同様、トップレベルで呼び出す。

```tsx
import { useReducer } from 'react';

function reducer関数(state, action) {
  switch (action.type) {
    case 'アクション':
      return 新しい値;
    // ...
    default:
      throw new Error('未知のアクションタイプ');
  }
}

function MyComponent() {
  // 引数の数により、2パターンある
  const [現在のstate, dispatch関数] = useReducer(reducer関数, 初期値);
  // または
  const [現在のstate, dispatch関数] = useReducer(reducer関数, 初期Arg, 初期化関数);
  // ...
}
```

### useReducerの引数

 第1引数 : reducer (りでゅーさー)
  - stateをどのように更新するかを指定するリデューサ関数
    - リデューサ？
        - 英語訳は`減速機`とか`薄め液`。
        - Jsでは[Array.prototype.reduce](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) というのがあるので、そっちの意味に近い。
          - 現在のステートとアクションを受け取り、新しいステートを返す関数 
            - つまり、複数を1つにまとめて(縮小)新たな値を出力すること。
    - アクション？
        - ステートをどのように変更するかを表現するもの(チョコになっちゃえ〜といった指示)


 第2引数 : initialArg 2パターン
  - 初期値
  - 引数が第3引数（関数）まであると、第3引数に渡す引数となる

 第3引数 : init
  - 初期化のための関数(後で説明)

### useReducerの返り値

```jsx
 const [現在のstate, dispatch関数] = useReducer(第1引数, 第2引数);
```

1 : 現在のstate
2 : stateを別の値に更新し、レンダーを発火するための関数(dispatch関数)
 
### dispatch関数 ?

```jsx
  onClick={dispatch({ type: 'チョコになっちゃえ' })}
```

ディスパッチされたアクションはreducer関数に渡され、その結果として新しいステートが返され、コンポーネントが再レンダリングされます


#### dispatch関数の引数
アクション
 - stateを別の値に変化させるための関数、dispatch関数には、唯一の引数としてアクションを渡す必要がある。
 - `{type : 'アクション'}` とする
     - アクションはuseReducerの`第1引数に設置した関数内`で使われる。(action.type)

返り値
 - 無し

#### dispatch関数の使用サンプル
- 例 : dispatch関数は`機械を操作するリモコン`と思っておく。
   - 電源のオンオフ、温度の強弱の調整、前に進め、後退しろ、前に蹴れ...といった命令を飛ばす。

```jsx
<button onClick={() => dispatch({ type: '電源ONOFF切り替えて' })}>電源</button>
<button onClick={() => dispatch({ type: '温度を1度上げる' })}>温度+1</button>
<button onClick={() => dispatch({ type: '風向きを自動にして' })}>風向き 自動</button>
```

```jsx
import { useReducer } from 'react';

// 指示をうけとって、現在のstateを変更する(指示と値を混ぜて1つにする)
function reducer(state, action) {
  if (action.type === '温度を1度上げる') {
    // state.温度 = state.温度 + 1; returnの前に値を変更してはいけない！
    return {
      温度: state.温度 + 1 // returnの中で値を変更する
    };
  }
  throw Error('不明な操作です');
}

export default function Counter() {
  const [state, dispatch] = useReducer(reducer, { 温度: 23 });
  return (
    <>
      <button onClick={() => {
        dispatch({ type: '温度を1上げる' }) // reducerに対して指示を出すだけ
      }}>
        温度を1度上げる
      </button>
      <p>現在の温度は {state.温度}.</p>
    </>
  );
}
```

![スクリーンショット 2023-10-13 9.10.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129861/bdfe98c6-b130-90cb-6561-2aa5d6cc0c80.png)


## 初期状態
> - 第3引数 : init : こっちも初期値だけど関数(後で説明)

引数が2つの場合
 - initialStateはステートの直接的な初期値として使われます。
     - `useReducer(関数, 初期値);`

引数が3つの場合
 - initFunction(initialArg)が呼ばれ、その結果が初期ステートとして使われます。
    - `useReducer(関数, 初期Arg, 初期化関数);`

```jsx

// useReducer引数が3つの場合

function 初期化関数(初期Arg) {
  // ここで初期値を処理（必要に応じて）
  return { ...初期値, 何かのプロパティ: '何かの値' };
}

function reducer関数(state, action) {
  switch (action.type) {
    case '特定のアクションタイプ':
      // 新しいステートを計算して返す
      return { ...state, 何かのプロパティ: '新しい値' };
    // ...
    default:
      throw new Error('未知のアクションタイプ');
  }
}

function MyComponent({ 初期値 }) { // 親から受け取った初期値をreducerに使いたいとか
  const [現在のstate, dispatch関数] = useReducer(reducer関数, 初期Arg, 初期化関数);
  // ...
  return (
      <button onClick={() => { dispatch({ type: '特定のアクションタイプ' })}}>特定のアクションタイプに変更して</button>
}
```

## useReducerの初期化時っていつなの？

下記3つを初期化時と言います。

1, ページを開いたとき(ルーティングによるページ遷移)
  - ページにアクセスしたときにコンポーネントはマウントされ、初期化処理が行われます。

2, コンポーネントが動的に追加されたとき
  - 例えば、ユーザーのアクションに応じて特定のコンポーネントがページに追加される場合（モーダルウィンドウの表示、リストへのアイテムの追加など）

3, 親コンポーネントが再マウントされたとき
親コンポーネントが何らかの理由でアンマウントされ、再度マウントされた時

## useState と useReducer どっちを選ぶ？

行いたい状態管理が簡単か、複雑かで選べば大丈夫です。

- useState
   - アクションが少なく、ロジックが単純な場合。
   - 単一の状態変数を管理している場合。
   - 状態が互いに独立している、関連が少ない場合
- useReducer
   - フォームの複数の入力フィールド、リストの並べ替えとフィルタリング、ゲームの状態管理 
   - 複数のサブ値を含む場合。
   - 状態の更新ロジックをコンポーネントから分離したい場合。
   - 同じ状態変更ロジックを複数のコンポーネントで再利用したい場合。
   - アクションによって状態の更新方法を詳細に制御したい場合。

---

お疲れ様でした！
少しは理解が深まれば幸いです！
より理解を深めるために、[公式のサンプルソース](https://ja.react.dev/reference/react/useReducer#examples-basic)を読み解いていきましょう！！