LoginSignup
0
0

[React] Reduxを理解する!

Last updated at Posted at 2024-06-07

Reduxとは?

Reduxとはグローバルな状態を管理するために使用されるライブラリです。

コンポーネント全体で管理すべき、グローバルな状態がReduxで管理されます。

  • ログイン状態
  • ローディング状態

グローバルな値を1つのStoreで管理することで、propsのバケツリレーから解放されます。

image.png

この記事では、Reduxの基本から状態管理について解説します。


Reduxの原則

Reduxは3つの基本原則で説明されます。

  • 単一ソースで全ての値を管理する
  • 状態は読み取り専用である
  • 状態の更新は純粋関数によって行われる


Reduxでの状態管理と更新の流れ

Reduxでの状態管理と、状態の更新は以下のデータフローによって行われます。

  1. 入力をトリガーとして、ActionCreatorが、対応するイベントを示すActionを作成
  2. データを管理するStoreへ、ActionDispatch(送信)される
  3. ActionReducer(状態を変更する純粋関数)に渡される
  4. Reducerによって生成された新しいStateが保存される
  5. 新しいStateViewがレンダリングする

92alq46m4gh0v1sprqgf46m3f38r.gif


Reduxの導入 ~ 状態管理

Reduxを使用するために、まずはライブラリをインストールします。

1. ライブラリのインストール

yarnを使用している場合
yarn add redux react-redux

npmを使用している場合
npm i redux react-redux


2. Action の定義

次に、Actionを作成します。

対応するイベントを示すActionを作成を行うActionCreatorを定義します。

// stores/action.ts
export const CounterActions = {
  INCREMENT: 'counter/increment',
  DECREMENT: 'counter/decrement',
} as const;

type ValueOf<T> = T[keyof T];

export interface CounterAction {
  type: ValueOf<typeof CounterActions>;
  payload?: unknown;
  error?: boolean;
  meta?: string;
}

// ActionCreators
export const increment = (): CounterAction => ({
  type: CounterActions.INCREMENT,
});

export const decrement = (): CounterAction => ({
  type: CounterActions.DECREMENT,
});

:pencil: Action

ReduxにおけるActionは、アプリケーションの状態を変更するための指示を含むオブジェクトです。
Actiontypeというプロパティを持ち、このtypeプロパティがアクションの種類を示します。また、必要に応じてpayloaderrormetaといった追加のプロパティを持つことができます。

:pencil: FSA

FSA(Flux Standard Action)は、Actionの標準形式を定めた規格です。
FSAに従うアクションオブジェクトは、次のプロパティを持ちます。

  • type:アクションの種類を示す文字列
  • payload?:アクションが関与するデータ
  • error?:アクションがエラーであることを示すブール値
  • meta?:アクションに関するメタデータ

Actionは基本的にはFSAに順守した形で作成するようにしましょう。


3. Reducerの定義

Actionの次は、状態を変更する純粋関数である Reducer の実装です。

Reducerは、prevStateActionを受け取り、newStateを返す純粋関数です。
Actionに応じた状態の更新処理を実装します。

// stores/reducer.ts
import { Reducer } from 'redux';

import { CounterAction, CounterActions } from './action';

export interface CounterState {
  count: number;
}

export const initialState: CounterState = { count: 1 };

export const counterReducer: Reducer<CounterState, CounterAction> = (
  state = initialState,
  action: CounterAction,
) => {
  switch (action.type) {
    case CounterActions.INCREMENT:
      return {
        ...state,
        count: state.count + 1,
      };
    case CounterActions.DECREMENT:
      return {
        ...state,
        count: state.count - 1,
      };
    // defaultの定義がないとエラーになるので注意
    default:
      return state;
  }
};

4. ActionをDispatcherに渡す

useDispatchフックを使用して、StoreActionを送信します。
送信されたActionは、Reducerによって処理され、状態が更新されます。

5. 状態の取得

useSelectorフックを使用して、Storeから状態を取得します。
セレクト関数は、Storeの状態全体を引数として受け取り、必要な状態を返します。

// Counter.tsx
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { decrement, increment } from './action';
import { CounterState } from './reducer';

const Counter: React.FC = () => {
  const count = useSelector<CounterState, number>((state) => state.count);
  const dispatch = useDispatch();

  return (
    <>
      <div>count: {count}</div>
      <div>
        <button onClick={() => dispatch(increment())}>increment</button>
      </div>
      <div>
        <button onClick={() => dispatch(decrement())}>decrement</button>
      </div>
    </>
  );
};

export default Counter;

6. Reduxストアの作成とプロバイダーの設定

最後に、Reduxストアを作成し、Reactアプリケーションに提供するためのプロバイダを指定しましょう。

// src/Providers.tsx
import { FC, PropsWithChildren } from 'react';

import { HelmetProvider } from 'react-helmet-async';
import { Provider as ReduxProvider } from 'react-redux';
import { BrowserRouter } from 'react-router-dom';
import { createStore } from 'redux';

import { counterReducer, initialState } from './reducer';

const store = createStore(counterReducer, initialState);
const Providers: FC<PropsWithChildren> = ({ children }) => (
  <BrowserRouter>
    <HelmetProvider>
      <ReduxProvider store={store}>{children}</ReduxProvider>
    </HelmetProvider>
  </BrowserRouter>
);

export default Providers;

Redux 公式スタイルガイド

Reduxを利用するにあたり、公式からでているスタイルガイドも一読しておきましょう。

個人的に注意しておきたい点をピックアップしておきます。

Action

  • Action名は「ドメインモデル/イベント種別」のフォーマットで定義する
  • ActionFSA(Flux Standard Action)に準拠させる
  • Actionは直に書かずAction Creatorを使って生成する

Design Pattern

  • ロジックを書くときはRedux Toolkitを使う
  • イミュータブルな状態の更新にはImmerを使う
  • ファイル構造にはFeature FolderまたはDucksパターンを適用する

まとめ

この記事では、Reduxの基本についてまとめてみました。
難しいイメージを持っていましたが、なんとかなった...

RTK(Redux Tool Kit)を使用した方が楽に実装できますが、プレーンなRedux実装についても理解しておくといい気がします。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0