LoginSignup
10
7

More than 1 year has passed since last update.

【図解付き】useReducerについて理解する

Last updated at Posted at 2022-06-29

はじめに

こんにちは。masakichiです。
今回は、useReducerについて簡単にまとめてみました。

useReducerの概要理解

useReducerとはstateを用意・管理するためのHooksです。
useState の代替として使用することもできます。

主に以下3つの登場人物を理解する必要があります。

dis.jpg

useStateとの比較

useStateと比較して、複数の値にまたがる複雑なstate ロジックがある場合などはuseReducerを使います。

また、useReducer を使うと、dispatchを下位コンポーネントに渡せるので、複数階層にまたがって更新を発生させるようなコンポーネントではパフォーマンスの最適化に繋がります。

useReducerについて

1.jpg

useReducerは2つの項目を持つ配列を返します。
1つ目はstateです。stateの初期値は、指定した初期状態に設定されます。
2つ目はstateを更新させるためのdispatch関数です。

引数
・reducer関数(stateの更新方法をまとめた関数)
・stateの初期値

返り値
・state
・dispatch関数(stateを更新する関数)

reducer関数について

2.jpg

stateの値を計算して更新するコードを記述した関数です。
慣習的に、switch文として書き、各caseに新しいstateを計算して返します。

引数
・更新前のstate
・actionオブジェクト(主にtypeとpayloadプロパティがある)

返り値
・reducerで更新された新しいstate

dispatch関数について

3.jpg
stateを更新するためのreducer関数を呼び出し、actionと呼ばれるユーザーが行ったことを表すオブジェクトを、reducer関数に渡します。

引数
・actionオブジェクト(主にtypeとpayloadプロパティがある)

返り値
・void

useReducerを実装する

それでは実際にuseReducerを使ってコードを書いていきます。
実装するものカウントアップとダウンができる簡単なものです。

なおコードは下記サイトのものを参考(ほぼコピペ)にさせていただきました。

Childコンポーネントを作る

react.tsx
import "./styles.css";
import { Child } from "./Child";

export default function App() {
  return (
    <div className="App">
      <Child />
    </div>
  );
}
Child.tsx
import React from "react";

export const Child: React.FC = () => {
  return (
    <div>
      <h1>カウント:</h1>
      <button>UP</button>
      <button>DOWN</button>
    </div>
  );
};
  • App.tsxに配置するChildコンポーネントを定義
  • 数値を更新するためのボタンを設置しておく

useReducerを定義する

Child.tsx
import React, { useReducer } from "react";//追記

const initialState = {//追記
  count: 0
};

export const Child: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState);//追記
  return (
    <div>
      <h1>カウント:{state.count}</h1>//追記
      <button>UP</button>
      <button>DOWN</button>
    </div>
  );
};
  • useReducerを定義する
  • useReducerの第二引数にわたす初期値をinitialStateとする
  • initialStateのcountプロパティとして0を定義

reducer関数を定義する

Child.tsx
import React, { useReducer } from "react";

type State = {//追記
  count: number;
};

type Action = { type: "INCREMENT" } | { type: "DECREMENT" };//追記

const reducer = (state: State, action: Action) => {//追記
  switch (action.type) {
    case "INCREMENT":
      return {
        ...state,
        count: state.count + 1
      };

    case "DECREMENT":
      return {
        ...state,
        count: state.count - 1
      };

    default:
      return state;
  }
};

const initialState = {
  count: 0
};

export const Child: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      <h1>カウント:{state.count}</h1>
      <button>UP</button>
      <button>DOWN</button>
    </div>
  );
};
  • reducer関数を定義し、引数にstateとactionをわたす
  • stateとactionの型定義をする
  • switch文を記述し、actionオブジェクトのtypeプロパティで分岐させる
  • typeプロパティが'INCREMENT'ならcountを1増やす
  • typeプロパティが'DECREMENT'ならcountを1減らす
  • stateは読み取り専用。stateのオブジェクトや配列は変更しないこと。
  • 新しく更新したstateをreturnする

dispatch関数を定義する

Child.tsx
import React, { useReducer } from "react";

type State = {
  count: number;
};

type Action = { type: "INCREMENT" } | { type: "DECREMENT" };

const reducer = (state: State, action: Action) => {
  switch (action.type) {
    case "INCREMENT":
      return {
        ...state,
        count: state.count + 1
      };

    case "DECREMENT":
      return {
        ...state,
        count: state.count - 1
      };

    default:
      return state;
  }
};

const initialState = {
  count: 0
};

export const Child: React.FC = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      <h1>カウント:{state.count}</h1>
      <button onClick={() => dispatch({ type: "INCREMENT" })}>UP</button>//追記
      <button onClick={() => dispatch({ type: "DECREMENT" })}>DOWN</button>//追記
    </div>
  );
};
  • ボタンのクリックイベントでdispatch関数を発火させる
  • dispatch関数の引数にはactionオブジェクトとしてtypeプロパティを渡す
  • typeプロパティはボタンがUPなら'INCREMENT'、DOWNなら'DECREMENT'にする
  • dispatch関数がreducer関数を呼び出すので、数値が更新される

コードリンク先

今回、gifにしたコードは下記リンクにあります。
https://codesandbox.io/s/usereducer-basic-6us96l

参考リンク先

今回の記事を執筆するにあたり下記リンク先を参考にさせて頂きました。

10
7
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
10
7