Reactキャッチアップへの道④ 『グローバルステートの管理』 (original) (raw)

この広告は、90日以上更新していないブログに表示しています。

こんにちは! スマレジ テックファームのMichiです!

前週に引き続き、Reactのキャッチアップをしていきます。今回は『グローバルステートの管理』について学びます。

グローバルステートの管理方法

Reactにおけるグローバルステートの管理方法は2つあります。

  1. Reactの標準機能であるContextを使う
  2. Reduxなどの外部ライブラリを使用する

本記事では、順番に両方とも解説していきます。

Contextを使用する方法

Reactには標準で『Context APIというコンポーネントツリー全体でデータを共有するための機能を提供しています。ここでは、簡単なカウンター機能を実装し、そのカウンター値をContextを使ってグローバル管理できるようにしてみます。

まずは、Contextを提供するためのコンポーネントを作成します。srcディレクトリ配下にprovidersという名称でディレクトリを作成し、その配下にCounterProvider.jsxコンポーネントを作成します。

providers/CounterProvider.jsx

import { createContext, useState } from "react";

export const CounterContext = createContext();

export const CounterProvider = (props) => { const { children } = props; const [count, setCount] = useState(0);

const increase = () => { setCount(count + 1); };

return ( <CounterContext.Provider value={{ count, increase }}> {children} </CounterContext.Provider> ); };

createContext関数を使って、CounterContextという新しいコンテキストを作成します。次に、CounterProviderという関数コンポーネントを定義し、カウンター処理の中身を記述します。

CounterProviderpropschildrenを受け取ります。また、rerurnしている<CounterContext.Provider>value には、グローバルで管理したい値や関数をオブジェクトの形式で渡します。こうすることで、囲っている{children}の要素の中で、Contextの値が使用できるようになります。

次に、カウンターを使用するコンポーネントを作成しましょう。

Counter.jsx

import { useContext } from "react";

import { CounterContext } from "./providers/CounterProvider";

export const Counter = () => {

const { count, increment } = useContext(CounterContext);

return (

Count: {count}

Increment
); };

他のコンポーネントからContextの値を使用するには、ReactのhooksであるuseContextを使います。

この例では、useContextに先ほど作成したCounterContextを引数として渡すことで、countincreaseを取得しています。Contextから取得したcountを表示し、increase関数を<button>のonClickイベントにバインドします。

最後に、アプリケーション全体でコンテキストを利用できるように設定します。

App.js

import { Counter } from "./Counter"; import { CounterProvider } from "./providers/CounterProvider";

export default function App() { return (

<CounterProvider>
  <Counter />
</CounterProvider>

); }

ルートコンポーネントであるApp.js内で、CounterコンポーネントCounterProviderでラップしています。これにより、Counter.jsx内でも、カウンター値をグローバルなステートとして扱えるようになりました。

外部ライブラリを使用する方法(Redux)

次に、外部ライブラリを使用する方法です。今回はReactの代表的な状態管理ライブラリである『Redux』を使用します。

まず最初に、Reduxを使用するにあたって必要な、『State, Reducer, Actions』の概念について簡単に解説します。

Reduxの基本概念:

ステート(State)

ステートはその名の通り、グローバルで状態管理される値のことを指します。このグローバルな状態は、Reduxのストアと呼ばれるコンテナに格納されます。

初期状態のステートは次のような形式のオブジェクトで定義されます。

const initialState = { count: 0 };

リデューサー(Reducer)

リデューサーは、ストア内のステートを更新するための関数です。リデューサーは、現在のステートとアクションを受け取り、新しいステートを返す役割を果たします。ステートの変更は、常にこのリデューサーを通してのみ行います。

リデューサーは次のような形式の関数で定義されます。第一引数にはステート(デフォルトには初期状態の値)、第二引数にはアクションを取ります。

const reducer = (state = initialState, action) => {

return newState; };

アクション(Actions)

アクションは、アプリケーション内で何が起こったかを示す情報のオブジェクトです。例えば、ボタンがクリックされた、データが取得されたなど、何らかのイベントや操作を表現します。アクションは、リデューサーに特定の処理を実行するよう指示するために使用されます。

アクションは以下のような形式のオブジェクトで表現されます:

const action = { type: 'ACTION_TYPE', payload: data };

実践

準備

では、実践編です。Contextの時と同じく、簡単なカウンター機能を実装します。

まず、Reduxのインストールとセットアップを行います。

npm install redux react-redux

次に、srcディレクトリ配下にstoreという名称でディレクトリを作成し、その配下にindex.jsファイルを作成します。

store/index.js

import { createStore } from "redux";

const initialState = { count: 0 };

export const INCREMENT = "INCREMENT"; export const DECREMENT = "DECREMENT";

const reducer = (state = initialState, action) => { switch (action.type) {

case INCREMENT:
  return {
    count: state.count + 1
  };

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

default:
  return state;

} };

const store = createStore(reducer);

export default store;

Contextを使用するときと同様に、Reduxの場合も、ストアを利用したい要素をReduxから提供されているProviderで囲む必要があります。<Provider>storeには、先ほどindex.jsで定義したstoreを渡します。

App.js

import { Provider } from "react-redux";

import { Counter } from "./Counter"; import store from "./store/index";

export default function App() { return (

<Provider store={store}>
  <Counter />
</Provider>

); }

ステートの利用

それでは、ストアのステートの値をCounter.jsxコンポーネントに表示させてみましょう。

ステートの値を取得するには、useSelectorというhooksを使用します。

Counter.jsx

import { useSelector } from "react-redux";

export const Counter = () => {

const count = useSelector((state) => state.count);

return (

Count: {count}

); };

ステートの更新

次は、ストアのステートの値をCounter.jsxから更新します。

ステートの値を更新するには、最初に述べた通りリデューサーを通して行う必要があります。このリデューサーを呼び出すための関数がdispatchです。

dispatchuseDispatchというhooksから取得できます。取得したdispatchにアクションタイプを伝えて、リデューサーの中のどの更新処理を呼び出すかを決定します。

import { useDispatch, useSelector } from "react-redux";

import { INCREMENT, DECREMENT } from "./store/index";

export const Counter = () => { const count = useSelector((state) => state.count);

const dispatch = useDispatch();

const increase = () => { dispatch({ type: INCREMENT }); }; const decrease = () => { dispatch({ type: DECREMENT }); };

return (

Count: {count}

Increment Decrement
); };

これで、Reduxのグローバルステート管理を利用した、カウンター機能を実装することができました。

どうやって使い分けるのか?

さて、ここまで学んだところで一つ思うところがあります。

「ContextとRedux、どうやって使い分けるねん?」と。

ContextとReduxのメリットを簡単にまとめてみました。

Contextのメリット

Reduxのメリット

まとめると、Contextはシンプルさがメリットで、小規模なアプリケーションや特定の小さい範囲での状態管理に適しているようです。

反対に、Redux(を含む外部の状態管理ライブラリ)は複雑で大規模なアプリケーションでの状態管理に向いており、ユーザー情報やアプリのマスタ情報などのアプリケーション全体で管理したい値に使用される傾向があります。

このあたりは、自分も実務でReactを触ったことがないので、想像しにくい場面ではあります。

まとめ

Reactキャッチアップの4週目は、ContextとReduxを使ったグローバルステートの管理方法についてでした。

さて、5月も最終週ですので、Reactの記事はいったんここで終わりにしたいと思います。来月からはTypeScriptのキャッチアップ記事を投稿する予定になります。

来月もまたよろしくお願いします。