「[[.NET 開発基盤部会 Wiki>http://dotnetdevelopmentinfrastructure.osscons.jp]]」は、「[[Open棟梁Project>https://github.com/OpenTouryoProject/]]」,「[[OSSコンソーシアム .NET開発基盤部会>https://www.osscons.jp/dotNetDevelopmentInfrastructure/]]」によって運営されています。

-戻る
--[[React]] -> [[Redux]]
--[[Reactのファースト・ステップ]]
--Reactのセカンド・ステップ
--[[Reactのサード・ステップ]]
--[[Reactの4thステップ]]
--[[Reactの5thステップ]]

*目次 [#a4c3ea2d]
#contents

*概要 [#c8d6c3ab]
create-react-appを使用した、[[React]] + [[Redux]]の step by step。

*手順1 [#fa5b6488]
色々悩んだが(と言うか、[[コレ>Reactのファースト・ステップ#n908d0bb]]の[[Redux]]化に失敗したため)、~
先ずは、以下の「Example: Todo List」のClass化版をやることに。

-React+Redux で Todoアプリを作ってみる │ Web備忘録~
https://webbibouroku.com/Blog/Article/react-redux-todo
-React Redux勝手にチュートリアル(TODO List) - TOEIC940点の文系プログラマー~
http://uraway.hatenablog.com/entry/2016/02/12/182048

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

**構成 [#s527e278]
 ─ src/
    ├─ App.js
    ├─ index.js
    ├┬ actions/
    │└─ Todo.js
    ├┬ components/
    │└─ Todo.js
    ├┬ containers/
    │└─ Todo.js
    ├┬ reducers/
    │└─ Todo.js
    └── createStore.js

**サンプルの生成 [#j3dbf15d]
 >create-react-app react-redux-todo

**インストール [#maeb5c00]
 >npm install --save redux react-redux redux-logger

**デバッグ設定 [#da9433e7]
[[デバッグ設定>Reactのファースト・ステップ#v9b02d5b]]を行っておく。

**実装 [#idc1c700]
以下を見ても明らかだが、

>Entry Point, Component, Action, Reducer

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

***Store作成 [#ca8d8207]
-createStore.jsを作成する。

-ポイント
--combineReducersをココで書いている。

--applyMiddlewareで、~
Reduxの状態遷移をコンソール上に表示する~
redux-logger ミドルウェアを追加する。

***Reducer作成(仮) [#h687216a]
-reducers/Todo.jsを作成する。~
[[前述のStore>#ca8d8207]]でimportしているReducerを仮で作成。

***[[Redux]]の組込 [#b10d5297]
-index.jsに組込む。
--createStoreして、storeを生成する。
--AppタグをProviderタグでラップしつつstore属性にstoreを設定。

-ここで一度 npm start コマンドを実行し動作することを確認。

***Component作成 [#ba4ac550]
-components/Todo.jsを作成する。
-そして、App.jsを修正してTodoを呼び出す。

***Action作成 [#v89cb346]
-actions/Todo.jsを作成する。

***Reducer修正 [#fd58d1c4]
-Reducer(仮)のreducers/Todo.jsにActionに対応した処理を実装する。
-Actionから渡された値を「処理して」Componentに渡す。の処理の部分。

-ポイント
--初期値はinitialStateで定義して使用する。
--state は書き換えるのではなく新たなオブジェクトとするので、~
Object.assignでディープコピーし、それに値を設定し、戻り値とする。
--

***Container作成 [#r8f048de]
-containers/Todo.jsを作成する。
-そして、App.jsを修正してTodoをComponentからContainerに切り替える。

-ポイント:ここでconnectする。

***Component修正 [#mcd78a14]
-components/Todo.jsで、propsのstateとfunctionを参照するように変更する。

**実行 [#sfd06e8d]
-Todoアプリを実行して動作確認する。

-[[デバッグ実行>Reactのファースト・ステップ#v9b02d5b]]すると、redux-logger ミドルウェアで、~
[[Redux]]の状態遷移はコンソール上に表示される。

**サンプル [#z14db030]
https://github.com/OpenTouryoProject/SampleProgram/tree/master/Template/SPATemplate/react-redux-todo

*手順2 [#m993fb4d]
「Example: Todo List」が動作したので、~
[[先程>#fa5b6488]]失敗した[[コチラ>Reactのファースト・ステップ#n908d0bb]]の[[Redux]]化に再チャレンジ。

**プロジェクトの準備 [#c9c35b8c]
-[[コチラ>Reactのファースト・ステップ#n908d0bb]]をコピーしてredux_appにリネーム。
-必要に応じて[[npmのインストール・コマンド>npm#ta17153d]]で~
node_modulesを復元する必要がある。
 npm i

**インストール [#t42a87de]
 >npm install --save redux react-redux redux-logger

**デバッグ設定 [#ae168770]
[[デバッグ設定>Reactのファースト・ステップ#v9b02d5b]]を行っておく。

**Component毎 [#tef34d40]

***実装 [#haacb1a8]
以下の辺りに注意しながら実装する。
-redux-loggerを使用
-createStoreの定義
-Actionの分割
-Reducerの書き方
-Containerの使用
-Componentからの参照方法

***実行 [#bbb13e6f]
-またも動かない。

-redux-loggerで、Reducersが動いていることは確認できるが、~
Component側が更新されない(State -> Componentの再実行がかかってない)。

-散々調べた挙げ句、原因は下で、

--combineReducersを使うと以下のようにStoreが階層化されるため、
 {"Menu1":{"counter":0},"Menu2":{"counter":0}}

--mapDispatchToPropsで、コレを考慮した設定にする必要があった。
 const mapStateToProps = state => {
   return {
     counter: state.Menu1.counter
   }
 }

-[[Redux]]さん、もっと、
--使い易さと、
--デバッグし易さを、

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

***参考 [#tffeb8df]
-combineReducersでハマったメモ~
https://qiita.com/usagi-f/items/ae568fb64c2eac882d05
-react-reduxで「dispatch is not a function」にハマった場合の対処法~
https://qiita.com/gaku3601/items/f77523bca6661f72f46a

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

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

***実行 [#xf51363b]
無事、動作!

***参考 [#t16b734d]
-Stack Overflow
--javascript - React & Redux : connect() to multiple components & best practices~
https://stackoverflow.com/questions/35032204/react-redux-connect-to-multiple-components-best-practices
--reactjs - React Redux: More containers v.s. less containers~
https://stackoverflow.com/questions/39377712/react-redux-more-containers-v-s-less-containers

-Qiita
--何をreduxのコンテナにするか~
https://qiita.com/halhide/items/b9c80b69630ac89b8797

**サンプル [#t7bf1183]
https://github.com/OpenTouryoProject/SampleProgram/tree/master/Template/SPATemplate/redux_app

*手順3 [#s4a24c70]
-改めて、[[コチラ>Reactのファースト・ステップ#gf8301c9]]の[[Redux]]化
-[[コチラ>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Core%20React%2BRedux%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88]]の下記の新しい要素も追加する。
--ページング処理
--Hot Reloading
--redux-thunkによる非同期処理

**プロジェクトの準備 [#f5f18271]
-[[コチラ>Reactのファースト・ステップ#gf8301c9]]をコピーしてredux_templateにリネーム。
-必要に応じて[[npmのインストール・コマンド>npm#ta17153d]]で~
node_modulesを復元する必要がある。
 npm i

**デバッグ設定 [#t88ebb02]
[[デバッグ設定>Reactのファースト・ステップ#v9b02d5b]]を行っておく。

**インストール [#maeb5c00]
-既知のモジュール
 >npm install --save redux react-redux redux-logger

-[[コチラ>https://techinfoofmicrosofttech.osscons.jp/index.php?ASP.NET%20Core%20React%2BRedux%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88]]の新しいモジュール
 >npm install --save redux-thunk react-router-redux node-noop history domain-task

**実装 [#p848397e]
-[[手順1>#fa5b6488]]の手順を参考に、本丸の[[Redux]]化に取り掛かる。
-Counter、FetchDataの順にモジュールを追加していくと良い。

***Store作成 [#sdb092fa]
-createStore.jsを作成する。

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

***Reducer作成(仮) [#f322ef52]
-仮のReducerを作成
-Counter、FetchDataの順にモジュールを追加

***[[Redux]]の組込 [#l64ccec4]
-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作成 [#sa661065]
作成済みなのでココでは何もしない。

***Action作成 [#l4ebab9a]
-Actionを作成
-Counter、FetchDataの順にモジュールを追加

-ポイント
--Counterは通常通り。
--FetchDataは
---非同期処理自体をReducerではなくココに定義。
---非同期処理の結果として、通常のActionを呼び出す。

***Reducer修正 [#g6ecabce]
-Reducer(仮)のreducers/Counter、FetchData.jsにActionに対応した処理を実装する。
-Actionから渡された値を「処理して」Componentに渡す。の処理の部分。

-ポイント
--初期値はinitialStateで定義して使用する。
--state は書き換えるのではなく新たなオブジェクトとするので、~
Object.assignでディープコピーし、それに値を設定し、戻り値とする。

***Container作成 [#gad2a8bd]
-containers/Counter、FetchData.jsを作成する。
-そして、routes.jsを修正してCounter、FetchDataをComponentからContainerに切り替える。

-ポイント:ここでconnectする。
--Counterは通常通り。
--FetchDataはActionに定義した非同期処理を呼び出す。

***Component修正 [#o4ef6ca6]
-components/Counter、FetchData.jsで、propsのstateとfunctionを参照するように変更する。
-なお、componentWillReceivePropsは無限ループ(stack overflow)防止コードが必要だった。
**実行 [#vc6436a4]
無事、動作!

**サンプル [#g981bbfd]
-https://github.com/OpenTouryoProject/FrontendTemplates/tree/develop/SPA/React/redux_template
-上記サンプルは、サーバー・サイドに[[ASP.NET Core>Reactのファースト・ステップ#o68564e4]]を利用している。

**参考 [#q01ddb23]
-BrowserRouterによるページング処理
--Access Route Params in React Router v4 | Jake Trent~
https://jaketrent.com/post/access-route-params-react-router-v4/

-redux-thunkによる非同期処理~
注意:react-reduxを使っているか?いないか?で、サンプル・コードが大きく異なる。
--React + ReduxでREST APIを叩いてリスト表示する方法~
https://qiita.com/kazmaw/items/a2def8978127ffb11f92

*[[次の手順へ(サード・ステップ)>Reactのサード・ステップ]] [#z34624a2]

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS