🌔

【useReducer】React hookが便利すぎる

6 min read

React hookとは..?

React hookはReact16.8から追加された機能で、クラスコンポーネントでしか使用できなかったstateなどのReactの機能を関数コンポーネントで使用できる機能です。
公式ページは以下です。

https://ja.reactjs.org/docs/hooks-intro.html

React hookのAPIについて紹介していこうと思います。
他のReact hookに関するAPIについても解説していますので、そちらもご覧ください。

useReducerとは...?

useReducer()useStateの代替であり、(state, action) => newStateという形のリデューサを受け取り、現在のstatedispatchとセットで返します。Reduxの知識があれば理解しやすいものかと思います。

Reduxはこちらの記事がわかりやすいかと思います。

https://qiita.com/kitagawamac/items/49a1f03445b19cf407b7

useStateuseReducerのどちらを使えばいいか迷うかと思います。useReducerを使う場合は、複数の値を使用した複雑なstateのロジックがある場合や、前のstateの値に基づいて、次のstateを決定する場合が挙げられます。また、useReducerを使用すれば、dispatchを下位コンポーネントに渡せることができるので、深い階層によるstateの更新でもパフォーマンスが落ちにくいようです。

使い方

  • useReducerにreducer関数とstateの初期値を渡します。
  • 戻り値は、statedispatchになります。
const [state, dispatch] = useReducer(reducer関数, stateの初期値);

dispatchとは...?

dispatchとは、引数にactionという、コンポーネントによって実行された操作を受け取ります。
主に{type: 捜査の種類, payload: 操作によって取得、また更新されるデータ}のように、typeプロパティ('action'の識別子)とpayloadプロパティ(データ)で構成されることが多い。

reducer関数とは...?

reducer関数は、stateactionを引数に受け取り、stateを更新する関数のことです。action.typeをみて、そのtypeに応じたstateの更新処理を記述します。

実際にコードで書いてみました。例として、数字をカウントするカウンターコンポーネントを作ってみました。また、API通信を使った場合も実装してみました。

  • useReducerを用いて数字をカウントする例
Counter3.jsx
import React, { useReducer } from 'react';

const Conter3 = () => {
    // reducerの関数を定義する。
    // stateとactionを引数に渡して、stateを更新する関数。
    const reducerFunction = (state, action) => {
        // actionのタイプによるstateの更新処理を記述する。
        switch (action) {
            case 'increment':
                return state + 1;
            case 'decrement':
                return state - 1;
            case 'reset':
                return 0;
            default:
                return state;
        }
    };

    // useReducerの引数にreducerの関数とステートの初期値を渡す。
    const [counter, dispatch] = useReducer(reducerFunction, 0);
    return (
        <>
            <p>カウント:{counter}</p>
            <button onClick={() => dispatch('increment')}>+1</button>
            <button onClick={() => dispatch('decrement')}>-1</button>
            <button onClick={() => dispatch('reset')}>RESET</button>
            <div className='line'></div>
        </>
    )
}

export default Conter3
App.jsx
import React from 'react';
import { Counter3 } from './components/index';

function App() {
  return (
    <div>
      <p>useReducerのサンプル1です</p>
      <Counter3 />
    </div>
  );
}

export default App;

以下のように動作します。

reducer関数で、actionの値に応じたstateの更新処理を記述しています。useReducerの引数には、reducer関数stateの初期値を渡しています。

  • useReducerを用いて数字をカウントする例
API.jsx
import axios from 'axios';
import React, { useReducer } from 'react';

const Address = () => {
    // 初期のステートを定義する。
    const initialState = {
        isLoading: true,
        isError: '',
        data: ''
    }

    // reducerの関数を定義する。
    const reducerFunction = (state, action) => {
        switch (action.type) {
            case 'init':
                return initialState;
            case 'success':
                return {
                    isLoading: false,
                    isError: '',
                    data: action.payload
                };
            case 'fail':
                return {
                    isLoading: false,
                    isError: 'エラーが発生しました。',
                    data: ''
                };
            default:
                return state;
        }
    }

    const [dataState, dispatch] = useReducer(reducerFunction, initialState);

    const fetchData = () => {
        axios.defaults.headers.post['Content-Type'] = 'application/json;charset=utf-8';
        axios.defaults.headers.post['Access-Control-Allow-Origin'] = 'http://localhost:3000/';
        // githubのAPIを叩く。
        const url = 'https://api.github.com/users/Tomoki-webpro';
        axios.get(url)
            .then(result => {
                const data = result.data;
                console.log(data)
                dispatch({ type: 'success', payload: data.login });
            })
            .catch(error => {
                dispatch({ type: 'fail' });
            });
    }

    return (
        <>
            <button onClick={fetchData}>githubからデータを取得する</button>
            <p>{ dataState.isLoading ? 'Loading...' : 'Finished!' }</p>
            <p>githubのユーザ名:{dataState.data}</p>
            <p>{ dataState.isError ? dataState.isError : '' }</p>
            <div className='line'></div>
        </>
    )
}

export default Address
App.jsx
import React from 'react';
import { API } from './components/index';

function App() {
  return (
    <div>
      <p>useReducerのサンプル2です</p>
      <API />
    </div>
  );
}

export default App;

以下のように動作します。(成功時)

以下のように動作します。(失敗時)

APIの通信には、axiosを使用しており、githubのAPIを叩いて、自分のgithubのユーザ名を取得しています。reducerFunctionaction.typeに応じたstateの更新をしています。dispatchでは、APIでデータの取得に成功した場合は、typesuccessにし、payloadに取得したユーザ名を格納しています。APIでデータの取得に失敗した場合は、typefailに更新しています。

まとめ

今回の記事ではuseReducerを紹介しました。次回はuseCallbackを紹介しようと思います。
githubにサンプルコードを載せていますので、気になった方はご覧ください。

https://github.com/Tomoki-webpro/react-hooks-study

参考記事

https://ja.reactjs.org/docs/hooks-reference.html#usereducer

https://qiita.com/seira/items/2fbad56e84bda885c84c

Discussion

ログインするとコメントできます