React Hooks ∋ useReducer

コンポーネントを Flux フロで管理したいならuseStateの代わりに使うのがいいかもしれません。特に管理する状態が多い場合はこちらを使うと処理を外部に切り分けられコードが見やすくなるのでお勧めします。

このフックは2-3の引数を受け取ります。1つ目は Reducer、2つ目はその Reducer の初期値、3つ目はオプショナルで2つ目の初期値が複雑な場合、それを更に弄る為の関数です。このフックは戻り位置に状態statedispatchという Reducer へアクションを流すための関数を返します。

です。

const init = initialState => {
  initialState.count = Math.floor(Math.random() * 10);

  return initialState;
};

const INCREMENT = "INCREMENT";
const DECREMENT = "DECREMENT";

const initialCountState = { count: 0 };

const countReducer = (state, action) => {
  switch (action.type) {
    case INCREMENT: {
      const nextState = { ...state };
      nextState.count++;
      return nextState;
    }

    case DECREMENT: {
      const nextState = { ...state };
      nextState.count--;
      return nextState;
    }

    default: {
      return state;
    }
  }
};

const App = () => {
  const [state, dispatch] = useReducer(countReducer, initialCountState, init);

  const increment = useCallback(() => {
    dispatch({
      type: INCREMENT
    });
  }, [dispatch]);

  const decrement = useCallback(() => {
    dispatch({
      type: DECREMENT
    });
  }, [dispatch]);

  return (
    <div className="App">
      <span>{state.count}</span>
      <button onClick={increment}>increment</button>
      <button onClick={decrement}>decrement</button>
    </div>
  );
};

useReducerには上記の説明のように(ここでは無理やり)3つの引数を渡してます。initialStateではcount0としてますが、init関数により0から9のどれかに書き換えられます。

アクションを発行する関数はuseCallbackで囲みます。この Reducer を使った更新ではdispatch関数は毎回変更が入ってしまい毎回アクション関数を新しく作ることになってしまいますが、依存しないpropsの更新が来た時などにはそれを防げる為です。今回はpropsがありませんが、そういった場合でも癖として常にやっておいたほうがいいかなと思います。

<button>をクリックするとcountReducerへアクションが飛びます。countReducerではそのアクションのtypeを見て捌きます。switch構文で捌くことが多いですが、if構文などでも構いません。

そしてcountReducerの戻り値が次のuseReducerの戻り値のstateへやってきます。そして、その値でコンポーネントが再描画される…という動作を繰り返します。