はじめに
前回のiOSエンジニアが苦しんだReduxの基礎(2)で素のReactと素のReduxを組み合わせたExampleについて見ていきました。
今回はconnect()
を使ったReact&ReduxによるWebサイトの実装について見ていきたいと思います。
では早速見ていきましょう。
Counterサンプルで学ぼう!
公式ReduxページのExampleの先頭に書かれている Counter を見ていきましょう。
本来は素のReactと素のReduxを使ったExampleではあるのですが、今回の説明のために改変します。
実装するWebサイトは下図の通りです。
実装されている機能としては下記の4つになります。
- 「+」ボタンを選択するとClick数が+1される
- 「-」ボタンを選択するとClick数が-1される
- 「Increment if odd」ボタンを選択するとClick数が奇数のときのみ+1される
- 「Increment async」ボタンを選択すると1秒後にClick数が+1される
前回と異なるのはReactとReduxの連携に connect() を利用しているという点です。
では1つ1つ見ていきましょう。
フォルダ構成
まずはフォルダ構成を見ていきます。
(説明のために一部変更を加えています。)
1 2 3 4 5 6 7 8 9 10 11 12 |
|
素の連携とconnect()による連携の比較
Actions
, Reducers
, Components
に関しては、前回と同じなので割愛します。
前回は、ReactとReduxの連携部分を下記のように書いていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
今回はこの連携をconnect()
を利用して実装します。
まずは、必要なモジュールを追加しましょう。
1 2 3 4 5 6 7 8 9 |
|
connect()
で連携します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
1つ1つ見ていきましょう。
connect()
は4つの引数をセットできるのですが、中でも重要なのが次の2つです。
mapStateToProps
mapDispatchToProps
です。
全てはreact-reduxのReadmeに書かれているのですが、ソースと合わせて見ていきます。
まずは、mapStateToProps
からです。
Readmeには、
If specified, the component will subscribe to Redux store updates. Any time it updates, mapStateToProps will be called. Its result must be a plain object*, and it will be merged into the component’s props. If you omit it, the component will not be subscribed to the Redux store.
と書かれていますね。
これはソースで比較しても明らかです。
前回までは、『 Stateの変更結果として描画に反映させる 』ために下記のようにしていました。
1 2 |
|
上記のように、store.subscribe
にrender
メソッドを渡すことで、dispatch
実行してState
の状態が変化したときに、毎回render
メソッドが実行されていました。
今回はconnect()
を利用しているのでstore.subscribe
が書かれていないことがわかると思います。
1 2 3 4 5 6 7 8 9 10 11 |
|
ですが、やっていることは同じで『Stateが変更されてStoreにそれが伝えられたときに mapStateToPropsは毎回実行 されます。』
もし、mapStateToProps
をconnect()
の第一引数に指定しなかった場合、『 Stateの変更結果として描画に反映させる 』ことができません。
また、return { value: state }
をすることでCounter Component
のpropTypes
であるvalue
に値を渡しています。
続いて、mapDispatchToProps
を見ていきます。
Readmeには、
If an object is passed, each function inside it will be assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a dispatch call so they may be invoked directly, will be merged into the component’s props. If a function is passed, it will be given dispatch.
と書かれていますね。
これは少々わかりづらいのですが、Counter Component
がクリックしたタイミングでstore.dispatch
にAction Creators
であるincrement
やdecrement
で作成したActions
を渡せるように実装することを実現しています。
前回までは、『 StoreにStateの変更を知らせる 』ために下記のようにしていました。
1 2 3 4 5 6 7 8 9 |
|
このように直接Counter Component
にonIncrement
およびonDecrement
を渡していました。
connect()
を利用すると、第二引数のmapDispatchToProps
の戻り値としてAction Creators
を設定することで実現できます。
これにより、Counter Component
のpropTypes
であるonIncrement
とonDecrement
に値を渡すことができます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
まとめ
これでconnect()
が何をしているのかが少しは見えてきました。
実行している処理内容がわかってくると、
connect()
: ReactとReduxをconnect
(接続)するmapStateToProps
:State
をProps
にmap
(マッピング)するmapDispatchToProps
:Dispatch
をProps
にmap
(マッピング)する
のように名称がそのものを表していたことが改めてわかります。
(理解促進してくれるような名称になっていますね。)
次回はさらに処理を簡略化して書くのに使われるredux-actions
を利用した実装について見ていきたいと思います。