React Hooks useReducerの使い方

React useReducer

こんにちは、ミナトです。

今回はReact HooksのuseReducerについて解説します。

useReducerとは?

useReducerはuseStateと同様に状態管理を行うフックです。useStateより複雑なstateを管理する場合に利用します。

useContextと組み合わせることによってReduxのような状態管理を行うことができます。

より複雑な状態管理を行うにはReduxを利用し、シンプルな状態管理であればuseReducer + useContextで実現できます。

useReducerの使い方

useReducerの引数にreducerとstateの初期値を渡します。そうすると、userReducerはstateとreducerにアクションを伝えるための関数dispatchを返します。

reducerとは、現在のstateとアクションを受け取り、新しいstateを返す関数です。

dispatchの引数にアクションを渡すことで、reducerが実行され、現在のstateとアクションを元にstateを変更します。

useReducerの実装例

説明だけだと分かりにくいので、実際に実装例で動作を確認してみましょう。

React Appの作成

まずはReactのアプリを新規作成します。作成方法については以下の記事を参考にしてください。

react_usestate

React Hooks useStateの使い方

2021年8月21日

コンポーネントの作成

componetを格納するディレクトリを作成します。(my-app/src/components/use_reducer

my-app/src/components/use_reducer の中にReducerComponents.jsを作成します。

今回の例では、ボタンを押した際に値を+-1するカウンターを実装しています。

  1. useReducerをインポート
  2. useReducerの第二引数に渡す初期値initialStateを定義
  3. reducerを定義
    reducerは引数に現在のstateとactionを受け取ります。actionのtypeに応じた処理を実行して、新しいstateを返します。
  4. コンポーネントの中でuseReducerを利用して、stateとdispatchを取得します。
    useReducerの第一引数には上で定義したreducerを第二引数にはinitialStateを指定します。
  5. コンポーネントでは、ボタンクリック時にdispatchを実行するようにしています。dispatchの引数にはアクションをオブジェクト形式で渡しています。
import React, {useReducer} from 'react';

const initialState = {count: 0};
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return {count: 0};
    default:
      return state;
  }
}

const ReducerComponent = () => {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <div>
      <h2>{state.count}</h2>
      <button onClick={() => dispatch({type: 'increment'})}>+1</button>
      <button onClick={() => dispatch({type: 'decrement'})}>-1</button>
      <button onClick={() => dispatch({type: 'reset'})}>Reset</button>
    </div>
  );
};

export default ReducerComponent;

最後にApp.jsを修正して、上記のコンポーネント表示します。

import './App.css';
import ReducerComponent from './components/use_reducer/ReducerComponent';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <ReducerComponent />
      </header>
    </div>
  );
}

export default App;

useReducer + useContextの実装例

続いてuseRedcerとuseContextを組み合わせて利用する方法を解説します。

useContextの使い方についてはこちらの記事をご確認ください。

React_usecontext

React Hooks useContextの使い方

2021年8月24日

Contextの定義

my-app/src/components/use_context の中にAppContext.jsを作成します。

import { createContext } from 'react';

const AppContext = createContext();

export default AppContext;

子コンポーネントと孫コンポーネントの作成

今回の例では、App.js > B.js > C.js という階層でコンポーネントを表示し、親のApp.jsでuseStateを用いて作成した、dispatchを孫のC.jsで呼び出して、stateを変更する例を実装してます。

my-app/src/components/use_reducer の中にB.jsとC.jsを作成します。

B.jsではC.jsを表示しています。

import React from 'react';
import C from './C';

const B = () => {
  return (
    <div>
      <C />
    </div>
  );
};

export default B;

C.jsでは、useContextを利用して、App.jsから渡されたdispatchを取得しています。

各ボタンをクリックした際、dispatchが実行されます。

引数には指定されたアクションに応じて、reducerが実行され、stateの値が変更されカウンターの表示が変更されます。

import React, {useContext} from 'react';
import AppContext from '../../contexts/AppContext';

const C = () => {
  const {dispatch} = useContext(AppContext);
  return (
    <div>
      <button onClick={() => dispatch({type: 'increment'})}>+1</button>
      <button onClick={() => dispatch({type: 'decrement'})}>-1</button>
      <button onClick={() => dispatch({type: 'reset'})}>Reset</button>
    </div>
  );
};

export default C;

親コンポーネントの修正

App.jsではreducerを定義しています。

useReducerで作成したdispatchを孫コンポーネントで取得できるように<AppContext.Provider>でコンポーネントを囲っています。また、valueにはオブジェクトとして、stateとdispatchを渡しています。

アプリを起動して、動作確認をするとApp.jsで定義したdispatchをC.jsで利用してstateの変更ができることが確認できます。

import './App.css';
import {useReducer} from 'react';
import AppContext from './contexts/AppContext';
import B from './components/use_reducer/B';

const initialState = {count: 0};
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return {count: 0};
    default:
      return state;
  }
}

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (

    <AppContext.Provider value={{state: state, dispatch: dispatch}}>
      <div className="App">
        <header className="App-header">
          <h2>{state.count}</h2>
          <B />
        </header>
      </div>
    </AppContext.Provider>
  );
}

export default App;

まとめ

まとめ
  • useReducerを利用することでuseStateより複雑な状態管理を行える
  • useContextとuseReducerを組み合わせることで子や孫コンポーネントからstateの参照や更新が可能
  • React単体ででReduxのような状態管理ができる

最後まで読んでいただき、ありがとうございます。

この記事が、「面白いな」、「勉強になったな」という方は、SNSでシェアしていただけると嬉しいです。

react_usestate

React Hooks useStateの使い方

2021年8月21日
React_useeffect

React Hooks useEffectの使い方

2021年8月23日
React_usecontext

React Hooks useContextの使い方

2021年8月24日