React useReducer Hook
1. useReducer
useReducer フックは、useState フックと似た性質を持っています。
大きな違いは、カスタムのステートロジック(State Logic) を構築できる点にあります。
もし、複雑なロジックに依存する複数のステートを同時に追跡・管理する必要がある場合、useReducer を使用するのが非常に有効です。
2. 構文 (Syntax)
useReducer フックは3つの引数を受け取ります。
useReducer(reducer, initialState, init)
- reducer: あなたのカスタムステートロジックを記述した関数です。
- initialState: 初期ステートを指定します。単純な値でも構いませんが、一般的にはオブジェクト(Object)が使用されます。
- init: ステートを初期化するために使用されるオプショナル(任意)の引数です。
useReducer フックは、現在のステート(state) と ディスパッチメソッド(dispatch method) を返します。
3. 実装例
以下は、useReducer を使用して2人のプレイヤーのスコアを追跡する例です。
import { useReducer } from 'react';
import { createRoot } from 'react-dom/client';
// 1. 初期ステートの定義
const initialScore = [
{
id: 1,
score: 0,
name: "ジョン",
},
{
id: 2,
score: 0,
name: "サリー",
},
];
// 2. リデューサー関数の定義
const reducer = (state, action) => {
switch (action.type) {
case "INCREASE":
// 対象のプレイヤーのスコアのみを +1 する
return state.map((player) => {
if (player.id === action.id) {
return { ...player, score: player.score + 1 };
} else {
return player;
}
});
default:
return state;
}
};
function Score() {
// 3. useReducerを初期化
const [score, dispatch] = useReducer(reducer, initialScore);
const handleIncrease = (player) => {
// 4. アクションをディスパッチしてステートを更新
dispatch({ type: "INCREASE", id: player.id });
};
return (
<>
{score.map((player) => (
<div key={player.id}>
<label>
<input
type="button"
onClick={() => handleIncrease(player)}
value={player.name}
/>
<span> スコア: {player.score}</span>
</label>
</div>
))}
</>
);
}
createRoot(document.getElementById('root')).render(
<Score />
);3.1 実装のポイント
この例では、プレイヤーの名前が書かれたボタンをクリックすると、dispatch 関数が呼ばれます。この関数は「何をしたいか」という指示(アクション)をリデューサー(reducer)に送り、リデューサーが新しいステートを計算して返します。
useState よりも記述量は増えますが、ステートの更新ロジックをコンポーネントの外部に切り出せるため、コードが読みやすく、テストしやすくなるというメリットがあります。