ReactのuseReducer入門:useStateとの違いと使い分け

スポンサーリンク

ReactのuseReducer入門:useStateとの違いと使い分け

useReducerとは

useReduceruseState の代替となるフックで、複数の状態や複雑な状態遷移を管理するのに適しています。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 入門」を参照してください。