.NET 開発基盤部会 Wiki」は、「Open棟梁Project」,「OSSコンソーシアム .NET開発基盤部会」によって運営されています。

目次

概要

create-react-appを使用した、React + Reduxの step by step。

手順1

色々悩んだが(と言うか、コレRedux化に失敗したため)、
先ずは、以下の「Example: Todo List」のClass化版をやることに。

ココでは、Web備忘録の方をやってみた。

構成

─ src/
   ├─ App.js
   ├─ index.js
   ├┬ actions/
   │└─ Todo.js
   ├┬ components/
   │└─ Todo.js
   ├┬ containers/
   │└─ Todo.js
   ├┬ reducers/
   │└─ Todo.js
   └── createStore.js

サンプルの生成

>create-react-app react-redux-todo

インストール

>npm install --save redux react-redux redux-logger

デバッグ設定

デバッグ設定を行っておく。

実装

以下を見ても明らかだが、

Entry Point, Component, Action, Reducer

と、複数のモジュールを行き来してシンドい。

Store作成

  • createStore.jsを作成する。
  • ポイント
    • combineReducersをココで書いている。
  • applyMiddlewareで、
    Reduxの状態遷移をコンソール上に表示する
    redux-logger ミドルウェアを追加する。

Reducer作成(仮)

  • reducers/Todo.jsを作成する。
    前述のStoreでimportしているReducerを仮で作成。

Reduxの組込

  • index.jsに組込む。
    • createStoreして、storeを生成する。
    • AppタグをProviderタグでラップしつつstore属性にstoreを設定。
  • ここで一度 npm start コマンドを実行し動作することを確認。

Component作成

  • components/Todo.jsを作成する。
  • そして、App.jsを修正してTodoを呼び出す。

Action作成

  • actions/Todo.jsを作成する。

Reducer修正

  • Reducer(仮)のreducers/Todo.jsにActionに対応した処理を実装する。
  • Actionから渡された値を「処理して」Componentに渡す。の処理の部分。
  • ポイント
    • 初期値はinitialStateで定義して使用する。
    • state は書き換えるのではなく新たなオブジェクトとするので、
      Object.assignでディープコピーし、それに値を設定し、戻り値とする。

Container作成

  • containers/Todo.jsを作成する。
  • そして、App.jsを修正してTodoをComponentからContainerに切り替える。
  • ポイント:ここでconnectする。

Component修正

  • components/Todo.jsで、propsのstateとfunctionを参照するように変更する。

実行

  • Todoアプリを実行して動作確認する。
  • デバッグ実行すると、redux-logger ミドルウェアで、
    Reduxの状態遷移はコンソール上に表示される。

サンプル

https://github.com/OpenTouryoProject/SampleProgram/tree/master/Template/SPATemplate/react-redux-todo

手順2

「Example: Todo List」が動作したので、
先程失敗したコチラRedux化に再チャレンジ。

プロジェクトの準備

インストール

>npm install --save redux react-redux redux-logger

デバッグ設定

デバッグ設定を行っておく。

Component毎

実装

以下の辺りに注意しながら実装する。

  • redux-loggerを使用
  • createStoreの定義
  • Actionの分割
  • Reducerの書き方
  • Containerの使用
  • Componentからの参照方法

実行

  • またも動かない。
  • redux-loggerで、Reducersが動いていることは確認できるが、
    Component側が更新されない(State -> Componentの再実行がかかってない)。
  • 散々調べた挙げ句、原因は下で、
  • combineReducersを使うと以下のようにStoreが階層化されるため、
    {"Menu1":{"counter":0},"Menu2":{"counter":0}}
  • mapDispatchToProps?で、コレを考慮した設定にする必要があった。
    const mapStateToProps = state => {
      return {
        counter: state.Menu1.counter
      }
    }
  • Reduxさん、もっと、
    • 使い易さと、
    • デバッグし易さを、

考えて設計して欲しい感がある。

参考

Componentを跨ぐ

Componentを跨ぐという初歩的なことも良く解らないので、
ネットを調べて以下の参考ページを発見したのでやってみる。

実装

Menu1、Menu2のContainerを集約するContainer, Action, Reducerを、Menu12に集約。

  • Containerネストは不可能なので(当時そう思っていた)、Containerを集約する。
  • 従ってContainer以外にも、 Action, Reducerの集約を行う。
  • 親Containerから子Componentへは、propsを使用してstateとfunctionを渡す。

実行

無事、動作!

参考

サンプル

https://github.com/OpenTouryoProject/SampleProgram/tree/master/Template/SPATemplate/redux_app

手順3

  • 改めて、コチラRedux
  • コチラの下記の新しい要素も追加する。
    • ページング処理
    • Hot Reloading
    • redux-thunkによる非同期処理

プロジェクトの準備

デバッグ設定

デバッグ設定を行っておく。

インストール

  • 既知のモジュール
    >npm install --save redux react-redux redux-logger
  • コチラの新しいモジュール
    >npm install --save redux-thunk react-router-redux node-noop history domain-task

実装

  • 手順1の手順を参考に、本丸のRedux化に取り掛かる。
  • Counter、FetchData?の順にモジュールを追加していくと良い。

Store作成

  • createStore.jsを作成する。
  • ポイント
    • combineReducersをココで書いている。
    • applyMiddlewareで、
      • Reduxの状態遷移をコンソール上に表示する redux-logger ミドルウェアを追加する。
      • 非同期処理を行うための thunk ミドルウェアを追加する。

Reducer作成(仮)

  • 仮のReducerを作成
  • Counter、FetchData?の順にモジュールを追加

Reduxの組込

  • index.jsに組込む。
    • createStoreして、storeを生成する。
    • AppContainer?タグをProviderタグでラップしつつstore属性にstoreを設定。
      (以下のようなスニペットを発見したので、そのまま適用)
      ReactDOM.render(
        <Provider store={store}>
          <AppContainer />
        </Provider>, ・・・
  • また、routes.jsにページング処理のためのBrowserRouter?を組込む。
    • BrowserRouter?のインポート
      import { BrowserRouter as Router, Route } from 'react-router-dom'
    • LayoutタグをBrowserRouter?のタグで囲む(なお、?はnull許容のもよう)
      <Router>
        <Layout>
          ・・・
          <Route path='/fetchdata/:startDateIndex?' component={ FetchData } />
        </Layout>
      </Router>
  • ここで一度 npm start コマンドを実行し動作することを確認。

Component作成

作成済みなのでココでは何もしない。

Action作成

  • Actionを作成
  • Counter、FetchData?の順にモジュールを追加
  • ポイント
    • Counterは通常通り。
    • FetchData?
      • 非同期処理自体をReducerではなくココに定義。
      • 非同期処理の結果として、通常のActionを呼び出す。

Reducer修正

  • Reducer(仮)のreducers/Counter、FetchData?.jsにActionに対応した処理を実装する。
  • Actionから渡された値を「処理して」Componentに渡す。の処理の部分。
  • ポイント
    • 初期値はinitialStateで定義して使用する。
    • state は書き換えるのではなく新たなオブジェクトとするので、
      Object.assignでディープコピーし、それに値を設定し、戻り値とする。

Container作成

  • containers/Counter、FetchData?.jsを作成する。
  • そして、routes.jsを修正してCounter、FetchData?をComponentからContainerに切り替える。
  • ポイント:ここでconnectする。
    • Counterは通常通り。
    • FetchData?はActionに定義した非同期処理を呼び出す。

Component修正

  • components/Counter、FetchData?.jsで、propsのstateとfunctionを参照するように変更する。
  • なお、componentWillReceiveProps?は無限ループ(stack overflow)防止コードが必要だった。

実行

無事、動作!

サンプル

参考

  • redux-thunkによる非同期処理
    注意:react-reduxを使っているか?いないか?で、サンプル・コードが大きく異なる。

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2021-06-16 (水) 17:49:54 (1038d)