React学習メモ:useReducer
1. useReducerとは?
- リデューサ (reducer) をコンポーネントに追加するための React フック
2. 基本的な使い方
-
コンポーネントのトップレベルで useReducer を呼び出す
-
引数としてリデューサ関数と初期状態を渡す
-
返り値として、現在の状態 (state) と、アクションを送信するためのディスパッチ関数 (dispatch)を受け取る
const [state, dispatch] = useReducer(reducer, initialArg, init?)
3. パラメータ (引数)
- reducer: 現在の状態とアクションを受け取り、次の状態を返す純粋関数
- initialArg: 初期状態の値
- init (任意): 初期状態を遅延して計算するための関数です。パフォーマンス最適化に利用できる
4. 返り値
- state: 現在の状態。最初のレンダリングでは initialArg(または init 関数の結果)がセット
- dispatch: ユーザー操作に応じて状態の更新をトリガーするための関数。この関数に「アクション」を渡して呼び出す
5. useState との使い分け
- 状態の更新ロジックが複雑な場合に useReducer が推奨される
- 多くのイベントハンドラが同様の方法で状態を更新する場合、ロジックをリデューサに一元化することで、コンポーネントが見やすくなる
- コンポーネントのパフォーマンス最適化にも役立つ
useStateとuseReducer:カウンターアプリで理解する違い
1. useStateを使ったカウンター
useStateを使った場合のカウンター
コンポーネント内で状態とその更新関数を直接管理
コード
import { useState } from 'react';
function Counter() {
// countという状態と、それを更新するsetCount関数を定義。初期値は0。
const [count, setCount] = useState(0);
// 「+」ボタンがクリックされたときに呼ばれる関数
const handleIncrease = () => {
// 現在のcountに1を足した新しい値で状態を更新
setCount(count + 1);
};
// 「-」ボタンがクリックされたときに呼ばれる関数
const handleDecrease = () => {
// 現在のcountから1を引いた新しい値で状態を更新
setCount(count - 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleIncrease}>+</button>
<button onClick={handleDecrease}>-</button>
</div>
);
}
2. useReducerを使ったカウンター
useReducerを使った場合のカウンター
状態更新のロジックをコンポーネントの外(reducer関数)に切り出す
コード
import { useReducer } from 'react';
// 状態更新のロジックを担当する「reducer関数」
// 2つの引数(現在の状態 state, どんな更新をしたいか action)を受け取る
function reducer(state, action) {
// actionのtypeプロパティに応じて、次の状態をどう変化させるか決定
switch (action.type) {
case 'increment':
return { count: state.count + 1 }; // countに+1した新しい状態を返す
case 'decrement':
return { count: state.count - 1 }; // countに-1した新しい状態を返す
default:
return state; // 想定外のactionの場合は、何も変更せず現在の状態を返す
}
}
function Counter() {
// useReducerをセットアップ
// 第1引数にreducer関数、第2引数に状態の初期値を渡す
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
{/* stateオブジェクトからcountプロパティを取り出して表示 */}
<p>Count: {state.count}</p>
{/* ボタンがクリックされたら、dispatch関数を使ってreducerに「お願い」を伝える。
この「お願い」がactionオブジェクト({ type: '...' })
*/}
<button onClick={() => dispatch({ type: 'increment' })}>+</button>
<button onClick={() => dispatch({ type: 'decrement' })}>-</button>
</div>
);
}