redux-toolkitでdispatch書きまくり問題をなんとかする

3 min read読了の目安(約2800字

概要

redux-toolkitって良いですよね。
ただ、コード書いてると「dispatchって書きまくりじゃね?」と思ったので、
なんとかしたいと思います。

環境作成

Create React Appでredux-toolkitかつtypescriptのテンプレートがあるので、
それを使っていきます。

npx create-react-app redux-toolkit-app --template redux-typescript

yarn startしてみると、こんな感じ

よくあるカウンターアプリですね。

カスタムフックを作る

別ファイル作った方が良いような気もするんですが、
counterSlice.tsに以下を追加します。

src/features/counter/counterSlice.ts
export const useCounter = () => {
  const dispatch = useDispatch();
  const { actions } = counterSlice;

  const increment = () => dispatch(actions.increment());

  const decrement = () => dispatch(actions.decrement());

  const incrementByAmount = (payload: number) =>
    dispatch(actions.incrementByAmount(payload));

  const incrementAsync = (amount: number) => {
    setTimeout(() => {
      dispatch(actions.incrementByAmount(amount));
    }, 1000);
  };

  return { increment, decrement, incrementByAmount, incrementAsync };
};

呼び出し側のコード修正

src/features/counter/Counter.tsx
export function Counter() {
  const count = useSelector(selectCount);
-  const dispatch = useDispatch();
+  const {
+    increment,
+    decrement,
+    incrementByAmount,
+    incrementAsync,
+  } = useCounter();
  const [incrementAmount, setIncrementAmount] = useState('2');

  return (
        <button
          className={styles.button}
          aria-label="Increment value"
-          onClick={() => dispatch(increment())}
+          onClick={increment}
        >
          +
        </button>
        <span className={styles.value}>{count}</span>
        <button
          className={styles.button}
          aria-label="Decrement value"
-          onClick={() => dispatch(decrement())}
+          onClick={decrement}
        >
          -
        </button>
          className={styles.textbox}
          aria-label="Set increment amount"
          value={incrementAmount}
          onChange={(e) => setIncrementAmount(e.target.value)}
        />
        <button
          className={styles.button}
-          onClick={() =>
-            dispatch(incrementByAmount(Number(incrementAmount) || 0))
-          }
+          onClick={() => incrementByAmount(Number(incrementAmount) || 0)}
        >
          Add Amount
        </button>
        <button
          className={styles.asyncButton}
-          onClick={() => dispatch(incrementAsync(Number(incrementAmount) || 0))}
+          onClick={() => incrementAsync(Number(incrementAmount) || 0)}
        >
          Add Async
        </button>
      </div>
    </div>
  );
}

感想

とりあえず、コンポーネントのコードからはdispatchを取り除く事ができました。
この例だとイマイチかもしれないんですが、別コンポーネントからもincrementしたい時に、
dispatchせずともカスタムフック呼び出せば良いので、そっちのが良いかなという感じです。

コード

今回のコードはこちらに置きました。

https://github.com/obuchi3/redux-toolkit-app