こんにちは、ミナトです。
今回は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のアプリを新規作成します。作成方法については以下の記事を参考にしてください。
コンポーネントの作成
componetを格納するディレクトリを作成します。(
)my-app/src/components/use_reducer
の中にReducerComponents.jsを作成します。my-app/src/components/use_reducer
今回の例では、ボタンを押した際に値を+-1するカウンターを実装しています。
- useReducerをインポート
- useReducerの第二引数に渡す初期値initialStateを定義
- reducerを定義
reducerは引数に現在のstateとactionを受け取ります。actionのtypeに応じた処理を実行して、新しいstateを返します。 - コンポーネントの中でuseReducerを利用して、stateとdispatchを取得します。
useReducerの第一引数には上で定義したreducerを第二引数にはinitialStateを指定します。 - コンポーネントでは、ボタンクリック時に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の使い方についてはこちらの記事をご確認ください。
Contextの定義
の中にAppContext.jsを作成します。my-app/src/components/use_context
import { createContext } from 'react';
const AppContext = createContext();
export default AppContext;
子コンポーネントと孫コンポーネントの作成
今回の例では、App.js > B.js > C.js という階層でコンポーネントを表示し、親のApp.jsでuseStateを用いて作成した、dispatchを孫のC.jsで呼び出して、stateを変更する例を実装してます。
の中にB.jsとC.jsを作成します。my-app/src/components/use_reducer
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でシェアしていただけると嬉しいです。