LoginSignup
0
1

More than 3 years have passed since last update.

react-hooks useReducerメモ

Posted at

useReducer

公式doc

位置づけ

通常、useReducer が useState より好ましいのは、複数の値にまたがる複雑な state ロジックがある場合や、前の state に基づいて次の state を決める必要がある場合です。また、useReducer を使えばコールバックの代わりに dispatch を下位コンポーネントに渡せるようになるため、複数階層にまたがって更新を発生させるようなコンポーネントではパフォーマンスの最適化にもなります。

ということで、場合分けの記述が出来たり、dispatchを下位コンポーネントに引き渡すことも可能とのこと。

よく見かけるreduce関数と違う

Javaとかのreduce関数とはちょっと違う。

useReducerの処理イメージ

useReducer関数により、管理対象のstate、stateを更新するdispatch関数を生成する。
dispatch関数の動作は、useReducerの第一引数reducerにて定義する。
管理対象のstateは、useReducerの第二引数、第三引数で初期値を与える/導出させる。
dispatch関数は任意のany型引数を受け取れる(=reducer関数で利用できる)。

何が良いのか

デザインパターンのストラテジーパターンを実現できる。
wikiの言葉を借りれば、

設計に優れた柔軟性をもたせることができ、かつ拡張に対して開放的であり変更に対して閉鎖的であるべきとする開放/閉鎖原則 (Open/Closed Principle, OCP) とも調和を保つことができる

言い換えれば、

  • useReducerの第一引数であるreducerにstateに対する処理が閉鎖的に記述できる
  • dispatch(action:any)により、どんな引数もreducerに渡せるという意味で拡張に開放的である

さらに
dipacth関数を子コンポーネントに渡せる。

useReducerの仕様


type useReducer = (reducer: reducer, initialArg: any, initializer: initializer) => dispatch: Function
type reducer = (state: object, action: any) => newState: any
type initializer = (initialArg: any) => initialState: any

※こんな書き方は出来ないがイメージ。

useReducer関数のシグネチャ

引数

  1. reducer関数のシグネチャを持つ関数。
  2. 初期state。
  3. オプション。初期化関数。第二パラメータを引数として起動し、初期stateを返却する関数。

返り値

  1. state
  2. dispatch関数

reducer関数のシグネチャ

引数

  1. 現在のstate。
  2. actionと呼称するanyオブジェクト。

返り値

reducerにて、計算した新たなstate

dispatch関数のシグネチャ

actionおよび現在のstateを引数にreducer関数が実行される。

引数

  1. actionと呼称するanyオブジェクト。

返り値

void

実装例

addとdeleteのactionを受け取れるreducerを定義してみた。

codesandbox


import React, { useReducer } from "react";
import "./styles.css";

export default function App() {
  const initialState = { data: [] };
  const [state, dispatch] = useReducer((state, action) => {
    if (action.type === "add") {
      return { data: state.data.concat(Math.random().toPrecision(2)) };
    }
    if (action.type === "delete") {
      const newData = Array.from(state.data);
      newData.splice(action.index, 1);
      return {
        data: newData
      };
    }
    return { data: state.data };
  }, initialState);

  return (
    <div className="App">
      <button onClick={() => dispatch({ type: "add", index: 0 })}>Add</button>
      <br />
      {state.data.map((e, index) => {
        return (
          <div key={"div_" + index}>
            <label>{index + ":" + e}</label>
            <button
              onClick={() => {
                dispatch({ type: "delete", index: index });
              }}
            >
              delete
            </button>
            <br />
          </div>
        );
      })}
    </div>
  );
}

0
1
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
0
1