moxt

Just another Blog site

ReduxのMiddlewareについて理解したいマン

      2016/01/29

ReduxのMiddlewareの仕組みがよく分からない。
具体的な処理過程を追いかけて理解に至るまでのメモ。

Middleware

Middleware?

ReduxではStore(正確にはStoreのdispatchかな)を拡張する仕組みとしてMiddlewareというものが用意されている。
考え方はNodeのフレームワークExpressのMiddlewareや、RubyのRackと同じと思ってる。

このMiddlewareを使ってロギング機能や非同期処理機能を搭載することができる。

applyMiddleware

ReduxではapplyMiddlewareという関数を使ってStoreにMiddlewareたちを積むことができる。

定義は下記の通り。

↑の処理内容をざっくり言うと、Middleware群でstoreのdispatchをマトリョーシカ人形の如く包んでる。
Middlewareの中にMiddleware、そのMiddlewareの中にMiddleware、、、最後にdispatch。
こうすることで、Redux本来のdispatchが動く前にMiddlewareたちの処理が実行されるわけ。

コード読む

applyMiddlewareは下記のように呼び出される。

これでMiddlewareに包まれたcreateStore、createStoreWithMiddlewareができる。

applyMiddleware定義をステップ毎にゆっくり見てゆく。

applyMiddlewareに...middlewaresを与えると、nextを引数にとる関数が返ってくる。
で、この『next引数にとる関数』にcreateStoreを突っ込んでる。

次はMiddlewareを活躍させるための下ごしらえをやってる。

次。

chain = middlewares.map(middleware => middleware(middlewareAPI))

見てのとおり、chainにはMiddlewareにmiddlewareAPIを与えた返り値リストが格納されてる。

繰り返しになるけど、middlewareAPIはStoreのgetStateとdispatchへの参照を持ったオブジェクト。
このオブジェクトを与えることで、Middlewareの中からgetStateとdispatchを呼び出すことができる。

なので、各Middlewareは引数としてmiddlewareAPIオブジェクトが与えられることを想定しておく必要なある。
たとえば、redux-thunkという非同期処理を行うためのMiddlewareはこんな感じだ。

{ dispatch, getState }と、middlewareAPIを受け取ってることが分かる。

ちなみにMiddleware(redux-thunk)にmiddlewareAPIを与えると次のような関数が返ってくる。

なので、chainは『オリジナルのStoreへの参照を持った関数を返す関数』のリスト、となる。
で、このchainをcomposeというシロモノを使い1つの関数にまとめる。

dispatch = compose(…chain)(store.dispatch)

composeはReduxのユーティリティ。
これは関数のリストを受け取って合成関数を返すシロモノ。
なので『関数を返す関数』たちの合成関数ができあがる。

ここで、compose(…chain)の具体的な処理を冗長に追ってみる。

composeはこれね。

chainは2つのMiddlewareを抱えるリストで…

と、する。
それぞれログを吐くMiddleware、非同期処理をやるためのMiddleware(redux-thunk)。

composeの中身はシンプルで、合成関数の作成はreduceRightを使って実現してることが分かる。

まずreduceRightの初期値、last(…args)はchainの最後の関数にargsを与えたモノ。
なので、nextにargsが入る。

で、この初期値がcomposedになるので、次の関数fの引数として与える。

次の関数fは…

なので

で、次の関数は存在しないのでreduceRightの処理はおしまい。
compose(..chain)の返り値は下記のようになる。

ログを吐くMiddleware -> 非同期処理を行うMiddleware(redux-thunk)という順番で処理が実行されることが分かるかと思う。

applyMiddlewareを見返すと…

composeで返ってきた関数にstore.dispatchを与えてる。

Middlewareの層の最下層にstore.dispatchが待ち構えている。
Storeのdispatch機能を保持したまま、Middleware群によって機能拡張されてる。

最後にオリジナルのstore(createStore)オブジェクトのdispatchを拡張dispatchでオーバーライドしたオブジェクトを返してる。
storeは独自のStore作成関数を使わないかぎりはreduxのcreateStoreになるかと。

これでMiddlewareを搭載したStoreができた。

 - javascript, プログラミング

  • このエントリーをはてなブックマークに追加
  • follow us in feedly

  関連記事

no image
Rubyのモジュール機能とRailsのHelperについて考える

Moduleとは 参考サイトを見ながら思ったことをメモ …

nokogiriでスクレイピングするときによく忘れるヤツ集

書くことで記憶を定着させる施術。 class,id以外の属性を指定してタグを探したい …

bindActionCreatorsで複数のアクションをdispatchに関連づけたい

react-reduxの公式見れば解決する話。 react-reduxでconnectするときに …

ReactNativeでGiphyのデータを表示する

まずは下記をサクッとパクってみる。 当方、比較的AndroiderなのでAndroidで。 …

no image
AndroidのHandlerって何?

Handlerは何?と、Handlerを直視するとHandlerの存在意義というかなんというか文脈を捉えることが難しい。 なので、まずはAndroidがシングルスレッドである、という所からスタートしてHandlerに向かってゆく。 …

no image
Macでdocker系のコマンドが使えなくなったら確認すること

OSXではdockerは使えないため、別にVMを立ち上げ、そこでdockerを動かしてる。 macからdockerコマンドを使うためにboot2dockerというコマンドを使う。 …

no image
iOSアプリの設計ってどうやるの?

ViewControllerに処理を詰め込みすぎて保守が大変になるのはあるあるネタですよね。 じゃあ、ViewControllerでやることってなんだろうって問われると、まあ、こんなんだろうなってフワッとしてる。 …

no image
意識低いRuby on Rails再入門4

下記の内容を読んでテスト系の処理をすっ飛ばしたメモ。 http://railstutorial.jp/chapters/sign-in-sign-out?version=4.0#top …

no image
YosemiteでRubyMineが起動できない

yosemiteからjavaが1.7系になってる。 一方、rubymineは1.6系を想定している。 …

ReactとFluxとReduxについて順を追って整理する

書き途中 Contents1 …