本文へスキップ
BecomeCoder

Reactコース · 第5章 状態の共有と再利用 · レッスン16

useReducerで更新ロジックを1か所にまとめる

ブラウザで完結

導入

第4章の TODO アプリ(レッスン12)を思い出してください。「追加」「削除」のように更新の種類が増えるほど、setItems(...) を呼ぶ場所があちこちに散らばっていきます。useReducer は「どう更新するか」を1つの関数(reducer)にまとめ、呼び出し側は「何をしたいか」を表す小さな命令(action)を送るだけにする書き方です。

説明

reducer(現在のstate, action) は「次の state」を返す関数です。dispatch(action) を呼ぶと React が reducer を実行し、その結果で state を更新します。

flowchart LR
  ui["UIのボタンなど"] -->|"dispatch({ type: '...' })"| reducer["reducer(state, action)"]
  reducer -->|"新しいstateを返す"| state["state"]
  state -->|"再描画"| ui

同じ TODO アプリを useReducer で書き直します。

function reducer(state, action) {
  switch (action.type) {
    case "add":
      return [...state, action.text];
    case "remove":
      return state.filter((_, i) => i !== action.index);
    case "clear":
      return [];
    default:
      return state;
  }
}

function App() {
  const [items, dispatch] = React.useReducer(reducer, ["牛乳を買う"]);
  const [text, setText] = React.useState("");

  function add() {
    if (text.trim() === "") return;
    dispatch({ type: "add", text });
    setText("");
  }

  return (
    <div style={{ fontFamily: "system-ui", maxWidth: 320 }}>
      <h2>やることリスト(useReducer版)</h2>
      <input value={text} onChange={(e) => setText(e.target.value)} placeholder="やることを入力" />
      <button onClick={add}>追加</button>
      <button onClick={() => dispatch({ type: "clear" })}>全部消す</button>
      <ul>
        {items.map((item, i) => (
          <li key={i}>
            {item}{" "}
            <button onClick={() => dispatch({ type: "remove", index: i })}>削除</button>
          </li>
        ))}
      </ul>
    </div>
  );
}
  • React.useReducer(reducer, 初期値)[state, dispatch] のペアを返します(useState[値, 更新関数] に対応する形です)。
  • dispatch({ type: "add", text }) … 「何をしたいか」を表すオブジェクト(action)を送るだけ。実際に配列をどう作り直すかは reducer の中だけに書きます。
  • 更新ロジックが1つの関数にまとまるので、「バグがあったら reducer を見ればいい」「reducer だけをテストできる」というメリットがあります。これは後で紹介する Redux と同じ考え方です。

やってみよう

reducer"addFront"(先頭に追加する)という action を追加し、ボタンから dispatch({ type: "addFront", text }) を呼べるようにしてみましょう。

実際に動かしてみよう

下のエディタにReactのコードを書くと、右側のプレビューにその場で描画されます。`function App() { ... }` を定義すると自動で表示されます(React・useState などは React.useState の形で使えます)。本文の例を打ち込んだり書き換えたりして、表示の変化を確かめながら進めましょう。

React — ブラウザ内で実行

JSXをその場で変換して描画する学習用React環境(React18 + Babel・同梱)を読み込みます。
スクロールして表示された時点でも自動で読み込まれます。