はじめに
こんにちは。masakichiです。
今回は、useReducerについて簡単にまとめてみました。
useReducerの概要理解
useReducerとはstateを用意・管理するためのHooksです。
useState の代替として使用することもできます。
主に以下3つの登場人物を理解する必要があります。
useStateとの比較
useStateと比較して、複数の値にまたがる複雑なstate ロジックがある場合などはuseReducerを使います。
また、useReducer を使うと、dispatchを下位コンポーネントに渡せるので、複数階層にまたがって更新を発生させるようなコンポーネントではパフォーマンスの最適化に繋がります。
useReducerについて
useReducerは2つの項目を持つ配列を返します。
1つ目はstateです。stateの初期値は、指定した初期状態に設定されます。
2つ目はstateを更新させるためのdispatch関数です。
引数
・reducer関数(stateの更新方法をまとめた関数)
・stateの初期値
返り値
・state
・dispatch関数(stateを更新する関数)
reducer関数について
stateの値を計算して更新するコードを記述した関数です。
慣習的に、switch文として書き、各caseに新しいstateを計算して返します。
引数
・更新前のstate
・actionオブジェクト(主にtypeとpayloadプロパティがある)
返り値
・reducerで更新された新しいstate
dispatch関数について
stateを更新するためのreducer関数を呼び出し、actionと呼ばれるユーザーが行ったことを表すオブジェクトを、reducer関数に渡します。
引数
・actionオブジェクト(主にtypeとpayloadプロパティがある)
返り値
・void
useReducerを実装する
それでは実際にuseReducerを使ってコードを書いていきます。
実装するものカウントアップとダウンができる簡単なものです。
なおコードは下記サイトのものを参考(ほぼコピペ)にさせていただきました。
Childコンポーネントを作る
import "./styles.css";
import { Child } from "./Child";
export default function App() {
return (
<div className="App">
<Child />
</div>
);
}
import React from "react";
export const Child: React.FC = () => {
return (
<div>
<h1>カウント:</h1>
<button>UP</button>
<button>DOWN</button>
</div>
);
};
- App.tsxに配置するChildコンポーネントを定義
- 数値を更新するためのボタンを設置しておく
useReducerを定義する
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関数を定義する
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関数を定義する
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
参考リンク先
今回の記事を執筆するにあたり下記リンク先を参考にさせて頂きました。