DEV Community

kaede
kaede

Posted on

React Redux Tutorial Part 2 -- counter アプリの incrementByAMount と incrementAsync を作成

why

https://react-redux.js.org/tutorials/quick-start

react-redux tutorial で counter アプリを作って
increment/decrement は実装して UI に組み込んだが
incrementByAmount は実装の途中で終わっていたので
その続きを codesandbox のリンクから追って進める。

incrementByAmount を実際に使えるようにする

https://codesandbox.io/s/github/reduxjs/redux-essentials-counter-example/tree/master/?from-embed=&file=/src/features/counter/Counter.js:359-423

Counter.js で

import React, { useState } from 'react';
import { decrement, increment, incrementByAmount } from './counterSlice'
Enter fullscreen mode Exit fullscreen mode

incrementByAmount で使う増加変数のために useState をインポート
incrementByAmount の reducer 本体をインポート

  const [incrementAmount, setIncrementAmount] = useState('2');
Enter fullscreen mode Exit fullscreen mode

増加量を useState を使って 2 で初期化

        <input
          aria-label="Set increment amount"
          value={incrementAmount}
          onChange={e => setIncrementAmount(e.target.value)}
        />
Enter fullscreen mode Exit fullscreen mode

増加量を変更できるロジックと UI を書き

        <button
          onClick={() =>
            dispatch(incrementByAmount(Number(incrementAmount) || 0))
          }
        >
          Add Amount
        </button>
Enter fullscreen mode Exit fullscreen mode

クリックしたら増加量である incremenAmount の数だけ
incrementByAmount が動き
incrementAmount に Number() を当てた値が 0 であれば増加量が 0 になるエラーハンドリングも当てる

Image description

Image description

これで、 incrementByAmount は実装できた。



incrementAsync を実装する

同じく codesandbox を参照。

CounterSlice.js の

export const { increment, decrement, incrementByAmount } = counterSlice.actions

export const incrementAsync = (amount) => (dispatch) => {
  setTimeout(() => {
    dispatch(incrementByAmount(amount))
  }, 1000)
}
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

incrementAsnync を追加で読み込み、
incrementByAmount と同様に incrementAmount を数値時にしてエラー処理して incrementAsync を動かすボタンを作る

Image description

これで、押してから 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)
    }
Enter fullscreen mode Exit fullscreen mode

state と action をそのまま渡した。
そして export/import してボタンを作ってセットしたが、
こっちは動かなかった。
この console.log のメッセージも表示されない。
同じ reducers の一つから別の reducer は呼び出せないと推測する。


まとめ

incrementByAmount は incrementAmount のローカルステートを作成し
その値を引数に渡して呼び出すだけなので楽だった。

incrementAsyncInside は、incrementByAmount を利用するので
reducers の外から dispatch で呼び出す必要があった。

Top comments (0)