why
https://react-redux.js.org/tutorials/quick-start
react-redux tutorial で counter アプリを作って
increment/decrement は実装して UI に組み込んだが
incrementByAmount は実装の途中で終わっていたので
その続きを codesandbox のリンクから追って進める。
incrementByAmount を実際に使えるようにする
Counter.js で
import React, { useState } from 'react';
import { decrement, increment, incrementByAmount } from './counterSlice'
incrementByAmount で使う増加変数のために useState をインポート
incrementByAmount の reducer 本体をインポート
const [incrementAmount, setIncrementAmount] = useState('2');
増加量を useState を使って 2 で初期化
<input
aria-label="Set increment amount"
value={incrementAmount}
onChange={e => setIncrementAmount(e.target.value)}
/>
増加量を変更できるロジックと UI を書き
<button
onClick={() =>
dispatch(incrementByAmount(Number(incrementAmount) || 0))
}
>
Add Amount
</button>
クリックしたら増加量である incremenAmount の数だけ
incrementByAmount が動き
incrementAmount に Number() を当てた値が 0 であれば増加量が 0 になるエラーハンドリングも当てる
これで、 incrementByAmount は実装できた。
incrementAsync を実装する
同じく codesandbox を参照。
CounterSlice.js の
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export const incrementAsync = (amount) => (dispatch) => {
setTimeout(() => {
dispatch(incrementByAmount(amount))
}, 1000)
}
increment, decrement, incrementByAmount
これらを export した後に
別で incrementAsnyc を定義して export する。
amount の他に、dispatch まで引数から受け取って
中で setTimeout を使い、incrementByAmount を dispatch している。
なぜ外部に書いているかは不明。
これを Counter.js で
import { decrement, increment, incrementByAmount, incrementAsync } from './counterSlice'
<button
onClick={() => dispatch(incrementAsync(Number(incrementAmount) || 0))}
>
Add Async
</button>
incrementAsnync を追加で読み込み、
incrementByAmount と同様に incrementAmount を数値時にしてエラー処理して incrementAsync を動かすボタンを作る
これで、押してから 1 秒後に反映される加算ボタンができた。
incrementAsync を reducers の中身に作って失敗した
counterSlide の外部にわざわざ新しく incrementAsync を作って、そこで dispatch して counterSlide の中の incrementByAmount 作るのは無駄に思えた。
なので reducers の内部から incrementbyAmount を呼ぶ
incrementAsyncInside を作ってみた。
reducers: {
incrementByAmount: (state, action) => {
console.log(`increment BY Async worked`);
state.value += action.payload
},
incrementAsyncInside: (state, action) => {
setTimeout(() => {
incrementByAmount(state, action)
}, 1000)
}
state と action をそのまま渡した。
そして export/import してボタンを作ってセットしたが、
こっちは動かなかった。
この console.log のメッセージも表示されない。
同じ reducers の一つから別の reducer は呼び出せないと推測する。
まとめ
incrementByAmount は incrementAmount のローカルステートを作成し
その値を引数に渡して呼び出すだけなので楽だった。
incrementAsyncInside は、incrementByAmount を利用するので
reducers の外から dispatch で呼び出す必要があった。
Top comments (0)