ReactのuseReducer入門:useStateとの違いと使い分け
useReducerとは
useReducer は useState の代替となるフックで、複数の状態や複雑な状態遷移を管理するのに適しています。Reduxと同じ「action → reducer → 新しい状態」というパターンで状態を更新します。
基本的な使い方
import { useReducer } from 'react' type State = { count: number } type Action = { type: 'increment' } | { type: 'decrement' } | { type: 'reset' } function reducer(state: State, action: Action): State { switch (action.type) { case 'increment': return { count: state.count + 1 } case 'decrement': return { count: state.count - 1 } case 'reset': return { count: 0 } } } function Counter() { const [state, dispatch] = useReducer(reducer, { count: 0 }) return ( <div> <p>{state.count}</p> <button onClick={() => dispatch({ type: 'increment' })}>+1</button> <button onClick={() => dispatch({ type: 'decrement' })}>-1</button> <button onClick={() => dispatch({ type: 'reset' })}>リセット</button> </div> ) }
useReducer(reducer, 初期状態) は [現在の状態, dispatch] を返します。dispatch に action を渡すと reducer が呼ばれて新しい状態が返ります。
actionにペイロードを持たせる
type Action = | { type: 'add'; payload: string } | { type: 'remove'; payload: number } type State = { todos: string[] } function reducer(state: State, action: Action): State { switch (action.type) { case 'add': return { todos: [...state.todos, action.payload] } case 'remove': return { todos: state.todos.filter((_, i) => i !== action.payload) } } } // 使う側 dispatch({ type: 'add', payload: '買い物' }) dispatch({ type: 'remove', payload: 0 })
useStateとの比較
useState |
useReducer |
|
|---|---|---|
| 向いている状態 | シンプルな値 | 複数フィールド・複雑な遷移 |
| 更新方法 | setter関数を直接呼ぶ | dispatch + action |
| ロジックの場所 | コンポーネント内 | reducer関数(外部化可) |
| テストのしやすさ | △ | ◎(reducer単体でテスト可) |
useStateで書くと複雑になるケース
// useState で複数の関連状態を管理するとバラバラになりがち const [isLoading, setIsLoading] = useState(false) const [data, setData] = useState(null) const [error, setError] = useState(null) // useReducer でまとめると状態が一元管理できる type State = | { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: Data } | { status: 'error'; error: string }
Redux Toolkitとの関係
useReducer のパターン(action → reducer → state)はReduxの考え方と同じです。
useReducer |
Redux Toolkit | |
|---|---|---|
| スコープ | コンポーネント内 | アプリ全体 |
| 状態の共有 | useContextと組み合わせる | Provider1つで全体に |
| 非同期処理 | 自前で実装 | createAsyncThunk |
| DevTools | なし | Redux DevTools |
コンポーネント内の複雑な状態管理には useReducer、アプリ全体で共有する場合は Redux Toolkit が適しています。
まとめ
| 概念 | 説明 |
|---|---|
state |
現在の状態 |
action |
何をするかを表すオブジェクト(type 必須) |
reducer |
(state, action) => 新しいstate の純粋関数 |
dispatch |
actionを送る関数 |
- 状態が1〜2個でシンプルなら
useState - 複数の関連状態・遷移パターンが多い場合は
useReducer - アプリ全体で共有が必要になったら Redux Toolkit へ
Reactのプロジェクト作成から始める場合は「React + Vite でプロジェクト作成」を参照してください。
シンプルな状態管理は「ReactのuseState入門」を、アプリ全体のグローバル状態管理には「Redux Toolkit 入門」を参照してください。