1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【React】ざっくりReducerのススメ

Posted at

Reducerのススメ

React勉強中ですが、Reducerがとんでもねぇものだということを伝えたく筆を執りました。

実際に使用した実感として、コンポーネント間でロジックや値、stateを共通化できるのが一番のメリットだと思っています。
あと、reducerのaction.typeを変えるだけで処理を切り替えることができるのも、何気に便利です。

ともあれ、さっそく、使ってみましょう!

実装

よく使われるbuttonコンポーネントの例でReducer使ってみます。 コードの参照はこのサイトから

Hoge.jsx
const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

ここで宣言しています。ざっくり左のstateにはinitializeState、dispatchにreducerを入れています。

Hoge.jsx
const [state, dispatch] = useReducer(reducer, initialState);

ここで、実際にdispatchの中にあるファンクションを呼び出しています。
ちなみに、onClickの中の「()=>」を消すと、無限ループバグになるときがあるので注意です。(renderごとにdispatchの中の処理が走り、stateが更新されると、再びrenderされ、再び読み込まれたdispatchが走ります)

Hoge.jsx
# 正しい
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
# 無限ループ
<button onClick={dispatch({type: 'decrement'})}>-</button>

以下は、先ほどの宣言時に入れていた値とファンクションの中身になります。

initializeStateでは値やstateを初期化しています。
reducerでは引数を受け取り、action,typeごとにそれぞれ処理を実行してくれます。

Hoge.jsx
const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

さきほど書いたdispatchでの括弧にあるtyoeが上のaction.typeで識別する値になります

Hoge.jsx
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>

発展

ここから簡単に発展させられるところとして、 ・ファイル分割 ・指定するaction.typeを楽に参照できるようにする があります。ざっくりこんな感じです。
Hoge.jsx
const initialState = {count: 0};

# ここ追加
export const actionTypes = () {
  increment:"increment",
  decrement:"decrement",
}

export function reducer(state, action) {
  switch (action.type) {
    case actionTypes.increment:
      return {count: state.count + 1};
    case actionTypes.decrement:
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}


function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: actionTypes.decrement})}>-</button>
      <button onClick={() => dispatch({type: actionTypes.increment})}>+</button>
    </>
  );
}

ここで追加したのは下記のコードです。
このコードの役割は、actiontypeで値を参照させることで、このReducerで使う単語を指定することができます。

Hoge.jsx
export const actionTypes = () {
  increment:"increment",
  decrement:"decrement",
}

また、べた書きしていた箇所を変えられます。

以下では、case文の値をべた書きではなく、参照して値を判定しています。

Hoge.jsx
export function reducer(state, action) {
  switch (action.type) {
    case actionTypes.increment:
      return {count: state.count + 1};
    case actionTypes.decrement:
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

またこちらではtypeで渡している値をべた書きではなく参照値にして、記載ミスがないようになっています。

Hoge.jsx
<button onClick={() => dispatch({type: actionTypes.decrement})}>-</button>
<button onClick={() => dispatch({type: actionTypes.increment})}>+</button>

参考

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?