React/Hooks/Lesson 10
useReducer — useStateが限界に達したとき、Reduxの基盤
35分·theory
このチャプター
2/5
TypeScript
useReducer — useStateが限界に達したとき、Reduxの基盤
💡 なぜ学ぶべきか?— useStateが煩雑になる瞬間がある
🎯
5〜6個の `useState` が1つのコンポーネントに積み重なり、互いに影響し合う瞬間 — 状態更新のコードは触れるたびに壊れやすくなっていきます。
💼
`useReducer` は、そうした状態を**単一オブジェクト + dispatch(action) パターン**にまとめます。どのアクションがどの変更を生み出すかがすべて reducer 関数に記述されており、追跡が容易です。
⚡
Redux Toolkit・Zustand・`useActionState`(React 19)— いずれも `useReducer` と同じ考え方に基づいています。このフックを理解することが、それらへの自然な入り口になります。
🔗
面接の定番質問: 「`useState` と `useReducer` の使い分けの基準は?」— 状態の数・複雑さ・複数箇所からの更新有無が判断のポイントです。
🏢 실무에서는
ショッピングカート(商品追加・数量変更・削除・全削除)、フォームウィザード(次へ・戻る・保存・検証)、コラボレーティブキャンバス(図形追加・移動・コピー・undo)— これらはすべて `useReducer` の守備範囲です。アクションの種類が増えても、reducer の1か所に分岐を追加するだけで対応できます。
reducer · action · dispatch — 3つの概念
1. シグネチャ
- ▸
reducer: (state, action) => newState という形の純粋関数 - ▸
dispatch(action): reducerを呼び出してstateを更新する
2. Discriminated Unionでactionの型を定義する
typeフィールド(タグ)で分岐するunion。switch文の中で、各caseごとにactionの追加フィールドが正確に推論されます。
3. reducer — 純粋関数、ミュートは絶対禁止
4. useStateとuseReducerの選択基準
💡 💡 useReducer実践 5選
1. reducerは必ず純粋関数にする
同じ(state, action)であれば常に同じ結果を返すこと。fetchやsetTimeoutのような副作用は禁止。
2. stateのミュートは絶対禁止
3. Discriminated Unionでactionの型を定義する
switch文の中で、caseごとにactionの各フィールドが正確に推論される。
4. neverでexhaustiveチェック
Actionに新しいtypeを追加してcaseを書き忘れると、コンパイルエラーで知らせてくれる。
5. Context + useReducer = ミニRedux
小規模なアプリではReduxを使わなくてもこれで十分。
⚡ 実際に試してみよう — reducerパターン
ショッピングカートのreducerにおけるアクション処理をシミュレーションします。
✏️ JS 코드
📟 コンソール出力
▶ 実行ボタンを押してください
⚠️ ブラウザのサンドボックスで実行 — console.log()のみ対応、alert/fetchは不可
確認クイズ
useReducerがuseStateより適している状況はどれですか?
先に読むとよい概念: useEffect
次のおすすめ: SyntheticEvent — イベントタイプ