Skip to content

DNET_Redux

nishi_74322014 edited this page Sep 11, 2026 · 1 revision

Redux

  • 戻る(Reactの該当節を参照)

概要

  • Fluxアーキテクチャに基づいて設計されたReact用フレームワーク
  • Fluxの影響を受けていることから、データの流れは一方向になる。
  • 「複数の画面で同じデータを共有し、更新頻度が高い複雑なアプリケーション」において最強の武器。

メリット

状態管理の一元化

アプリケーション全体の「状態(State)」を1つの大きなツリー(Store)で管理(Single Source of Truth)。

  • コンポーネント間でデータをバケツリレー(Props Drilling)する必要がなくなる。

  • これにより、データの不整合が起きにくくなり、デバッグが容易になる。

  • Reduxによる、バケツリレー実装のソリューション

    • コンポーネントの縦方向(深さ)に対してバケツリレー実装が増える(中間コンポーネントが不要なpropsを中継)。
    • コンポーネントの横方向(幅)に対してバケツリレー実装が増える(共通の親が仲介者として状態を持たされる)。
    • トップに1つのStore、使う状態をSliceで分け、ページによってReduxを使用する・しないを変える事が出来る。

予測可能性と一貫性

状態は直接変更できず「Reducer」という純粋関数を通じてのみ状態を更新。

  • 「いつ、どこで、誰が、なぜ」状態を変更したのかが完全に追跡可能に。
  • 複雑なロジックでも、同じアクションを与えれば必ず同じ状態に遷移する。

強力なデバッグツール

開発を強力にサポートするブラウザ拡張機能がある(Redux DevTools)。

  • 過去に発行されたアクションを遡ったり、特定の時点の状態に戻したりできる。
  • 全ステートをリアルタイムで監視・編集できるため、早期に不具合の原因特定が可能。

テストのしやすさと保守性

「Reducer」は、外部に依存しない純粋関数として記述。

  • 副作用がないため、単体テスト(Unit Test)を書くのが非常に簡単。
  • コードの品質が向上し、メンテナンスがしやすくなる。

デメリット

学習コストが比較的高く、記述量が増えるため、小規模開発ではオーバー・エンジニアリング。

一貫性

状態遷移が明確でバグが減るが、記述量(ボイラープレート)が増える。

デバッグ

タイムトラベル機能で追跡が容易だが、学習コストが比較的高い。

拡張性

大規模でも秩序を保てるが、小規模ではオーバー・エンジニアリング

特徴

  • Actions -> Reducers -> Storeの3つの部分から構成される。
  • Storeが状態を持ち、Actionが発生した際に、Reducerを使ってStoreの状態を更新する。
  • Viewに関しては、Storeの用意するAPIを使うことで、状態の購読、更新・取得ができる。

三原則

Single source of truth

状態は一つのStoreのobjectツリーに格納される。

State is read-only

Actionを発火することが、状態を更新する唯一の方法。

Changes are made with pure functions

状態がActionによってどのように変更されるか、
定義するために純粋な(副作用のない)Reducerを書く。

ドメイン

Actions

  • View等から発火されて作られるオブジェクト

    • 実体

      {
          type: "アクションの種類を一意に識別できる文字列またはシンボル",
          payload: "アクションの実行に必要な任意のデータ",
      }
    • 定義(actions.js)

      export const ACTION_TYPE = 'アクションの種類を一意に識別できる文字列またはシンボル';
      export const ActionType = hoge_value => ({type: ACTION_TYPE , payload: hoge_value });
  • Viewのconnect関数のmapDispatchToProps引数(デリゲート)で定義・生成される。

Reducers

  • Flux の Dispatcher(Fluxの該当節を参照)の代替。

  • 関数型プログラミングにおいて畳み込み演算を意味する副作用のない関数。

    • 初期状態はデフォルト引数で定義される。
    • 状態を変更するには、新しいものを合成するように書く。
  • 定義(reducer.js)

    import { ACTION_TYPE } from './actions';
    
    export default (state = {value: 0}, action) => {
        switch (action.type) {
            case ACTION_TYPE:
                return { ...state, value: state.value + action.payload };
            default:
                return state;
        }
    }
    • 大規模な開発においてReducerを細かく分割する場合は、
      combineReducersという関数を用いて書く。

      import { combineReducers } from 'redux';
      
      const XXXXReducer = (state = {...json...}, payload) => {
          /* 省略 */
      };
      const YYYYReducer = (state = {...json...}, payload) => {
          /* 省略 */
      };
      const ZZZZReducer = (state = [...json...], payload) => {
          /* 省略 */
      };
      export default combineReducers({
          XXXX: XXXXReducer,
          YYYY: YYYYReducer,
          ZZZZ: ZZZZReducer,
      })

Store

  • シングルトンで、インスタンスの管理不要。
  • 状態(state)を格納する。
  • アプリケーションに必ず1つしか設けられない。
  • 1つのStoreですべての状態を管理する。
  • イメージとしては「でっかいJSONの塊」。

View

  • Reduxに参加するためにはReactReduxによって提供されるconnect関数を用いる。

    • react-reduxをインストールして、

      npm install react-redux --save
      
    • react-reduxをインポートする。

      import { connect } from 'react-redux';
  • 変更は、propsを通じて渡されてくるので、

    connect(mapStateToProps, mapDispatchToProps)(Component)
    • connect関数のmapStateToProps引数(デリゲート)は、stateとpropsのバインディングを定義する。

      • 以下のように書いても動作するが、

        state => state
      • 以下のように必要なものだけを選別してpropsにバインドする。

        state => ({ value: state.value })
    • connect関数のmapDispatchToProps引数(デリゲート)は、

      • dispatchで、Reducerに向けた通知を定義する。

        { ActionType }
      • Actionsの定義は、以下のようにインポートする。

        import { ActionType } from './actions';
  • Container

    • 以下のようなケースでは、Containerが集約してconnect関数でバインドする。

      (<UsersList>
          <User />
          <User />
          <User />
          <User />
      </UsersList>)
    • 可読性を高めるため、Componentとディレクトリが分けられることが多い。

Fluxとの違い

概要(Fluxとの違い)

Fluxの場合

Reactコンポーネント自身が個別に状態管理をする。

Reduxの場合

  • 状態管理する専用の場所(Flux の Store)で状態管理する。

  • Reactコンポーネントはそれを映すだけに徹する。

  • コードの削減と関数の再利用性の向上

    • Dispatcher(Fluxの該当節を参照)がない
    • Store(Fluxの該当節を参照)がシングルトンでインスタンス管理が不要。

参考(Fluxとの違い)

Saga

概要(Saga)

  • Reduxは、最小限で、フルスタックとは言えない薄さ。
    (なので、機能を補う幾つかのサブ・プロジェクトがある)

  • Reducerの中には副作用を生む処理を書いてはいけない。

  • 副作用を生む処理の設計の指針について、
    模索が必要で、その筆頭が 非同期処理の扱いになる。

    • 処理をどこに書くのか、
    • どのように書くのか、
    • どこから呼び出すべきか、
  • 解決方法としてredux-sagaがある。

詳細(Saga)

(元 Wiki では未記載)

参考(Saga)

redux-saga

その他(Saga)

  • redux
    • redux-thunk
    • redux-promise
  • react-side-effect

関数型言語の副作用

概要(副作用)

  • 「戻り値の値」を変えることを「作用」
  • 「戻り値以外の値」を変えることを「副作用」

参考(副作用)

ツール類

以下のようなツールが存在しているらしい。

Redux DevTools

Redux Toolkit

Reduxの問題点

感想

  • モジュールが分割できるのは良い。

  • ただし、

    • トラブル・シューティングが困難

    • パターン

      • ...から外れると途端に(設計/実装に関して)何をしてイイか解らなくなる。
      • ...を決めて最小セットを作成してそれに準拠して開発する必要がある。
  • やった感想として、

    • 複雑でパターン化&RADのIDEによるサポートが無いと厳しい気がする。
    • 早々に、Hooksに行ってしまうのがイイのかも知れない。

参考(Reduxの問題点)

参考

Qiita

POSTD

Medium

terrierscript

inuscript

Reactのセカンド・ステップ

Reactのセカンド・ステップ

マイクロソフト系技術情報 Wiki

移行メモ

  • 「アプリケーションに必ず1つしか設けらない。」→「設けられない。」に修正した。
  • 「Fluxとの違い」の節にある Store / Dispatcher のリンクは、 元 Wiki では同ページ内アンカ(#p3c60442 / #o1ac7ccf)として書かれていたが、 実際には Flux ページ側のアンカのため、同ページの該当節への参照に置き換えた。
  • 「定義(actions.js」「定義(reducer.js」の閉じ括弧の欠落を補った。
  • 同名の見出し(「概要」「参考」「詳細」「その他」)が複数あり GitHub Wiki でアンカが衝突するため、括弧で文脈を補って一意にした。
  • マイクロソフト系技術情報 Wiki(techinfoofmicrosofttech.osscons.jp)への URL リンクは、移行済みの ASP.NET Core React+Reduxテンプレート に張り替えた。
  • PukiWiki のページ内アンカ(#xxxxxxxx)は GitHub Wiki では再現できないため、 同一ページ内のアンカは見出しから生成されるアンカに張り替え、 他ページのアンカを指すリンクは「〜(ページ名 の該当節を参照)」の形に置き換えた。

Tags: 移行, Redux, React, Flux, Store, Reducer, Action, 状態管理, Redux Toolkit, redux-saga

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally