UseReducerの基本的な使い方
はじめに
UseReducer
はUseState
と同じようにコンポーネントの中にstate
と呼ばれる状態
と初期値
を定義するところまでは同じ。
UseState
と異なるのは定義した時点で状態
の値に対して、どんな更新を行うのか定義できるところ。
使用例
import { useState, useReducer } from "react"
const Example = () => {
// (2)
const rFunction = (prev, {action, value}) => {
switch(action) {
case "up":
return prev + value;
case "down":
return prev - value;
default:
throw new Error("定義されていないactionです。");
}
};
// (1)
const [rstate, dispatch] = useReducer((prev, { action, value }) => {
rFunction(prev, { action, value })
}, 0);
// (3)
const rAddCount = (value) => {
// 初期値が決められた段階で既にどんな更新を行うのか定義済み
dispatch({ action: "up", value: value });
};
const rMinusCount = (value) => {
dispatch({ action: "down", value: value });
}
return (
<>
<div>
<h3>{ rstate }</h3>
<button onClick={ () => rAddCount(1) }> +1 </button> <!-- (4) -->
<button onClick={ () => rAddCount(2) }> +2 </button>
<button onClick={ () => rMinusCount(1) }> -1 </button>
<button onClick={ () => rMinusCount(2) }> -2 </button>
</div>
</>
);
};
export default Example;
(1)定義
const [rstate, dispatch] = useReducer((prev, { action, value }) => {
rFunction(prev, { action, value })
}, 0);
useReducer
を呼び出した後、第一引数に更新を実行する関数を、第二引数に初期値を設定。
第一引数に渡す更新処理が返り値のdispatch
メソッドを呼び出した時に行う処理になる。
今回の場合、
関数は(prev, { action, value }) => { rFunction(prev, { action, value }) }
の部分。
初期値は0
。
関数についてprev
は前の状態
の値。{ action, value }
はdispach
メソッドが引数として受け取る値。
dispach
メソッドが呼ばれた後、内部でrFunction
メソッドが呼ばれる。書き方によってはここに直接、処理をアロー関数で記述してしまっても問題ない。
(2)実際の更新処理
const rFunction = (prev, {action, value}) => {
switch(action) {
case "up":
return prev + value;
case "down":
return prev - value;
default:
throw new Error("定義されていないactionです。");
}
};
(prev, { action, value }) => { rFunction(prev, { action, value }) }
の記述部分でrFunction
にprev
(前の状態
の値)とaction
(処理)とvalue
(前の状態
の値に与える影響)のプロパティを持つオブジェクトを渡す。
※action
(処理)を引数に渡す処理は今の所よく見受けられるが、value
(前の状態
の値に与える影響)を渡して良いものかまだ不明。
処理内容としてはaction
がup
ならvalue
分、加算。action
がdown
ならvalue
分、減算。
(3)dispatchの利用
const rAddCount = (value) => {
// 初期値が決められた段階で既にどんな更新を行うのか定義済み
dispatch({ action: "up", value: value });
};
const rMinusCount = (value) => {
dispatch({ action: "down", value: value });
}
...中略
<button onClick={ () => rAddCount(1) }> +1 </button>
<button onClick={ () => rMinusCount(1) }> -1 </button>
ボタンを押した際に() => rAddCount(1)
、もしくは() => rMinusCount(1)
を実行。
それぞれのメソッドの内部でdispatch
メソッドにaction
とvalue
を渡して、さらに内部のrFunction
を呼び出している。
こんな書き方をしても良いのか?
const countControle = (action, value) => {
dispatch({ action: action, value: value });
};
...中略
<button onClick={ () => countControle("up", 1) }> +1 </button>
<button onClick={ () => countControle("down", 1) }> -1 </button>
さらに
直接dispatch
を呼んでも。
これが一番わかりやすいかも?
<button onClick={ () => dispatch({ action: "up", value: 4 }) }> +4 </button>
おまけ... (4)イベントハンドラーに渡す引数を渡す時
return (
<>
<div>
<h3>{ rstate }</h3>
<button onClick={ () => rAddCount(1) }> +1 </button> <!-- (4) -->
<button onClick={ () => rAddCount(2) }> +2 </button>
<button onClick={ () => rMinusCount(1) }> -1 </button>
<button onClick={ () => rMinusCount(2) }> -2 </button>
</div>
</>
);
今まで<button onClick={rMinusCount}> -1 </button>
の書き方をしていたが
引数を渡したい時には<button onClick={ () => rMinusCount(1) }> -1 </button>
のように中でアロー関数を定義し、さらにその内部でrMinusCount
メソッドを引数付きで呼び出せば良い。
UseStateとの違い
-
UseState
は初期値の定義のみだが、UseReducer
は初期値に加えて更新方法も定義時に指定することができる。- 定義している箇所が一箇所なのでコードの見通しが良くなる。
- 更新方法が管理しやすくなるので開発規模が大きくなった時に威力を発揮する。
Discussion