Fluxのドキュメントページにある、Actions and Dispacherというページを日本語訳してみた。
※ わーと、っと訳してしまったので、随時なおしていく。誤訳等あればご指摘下さい。
Dispatcherとは?
DispatcherはFluxアプリケーションのデータフローの中央ハブとなるSingletonである。それは、本質的にコールバックのレジストリであり、登録されたコールバックを呼び起こすことができる。各StoreはDispacherにコールバックを登録することができる。新しいデータがDispatcherに入ると、Disptacherは登録済みのコールバックを用いてStoreにデータを伝搬する。dispatch()メソッドを通じてコールバックを呼び出す。dispatchメソッドはデータペイロードオブジェクト引数にとる。このペイロードオブジェクトは一般的にアクションと同義である。
ActionとAction Creatrors
新しいデータがシステムに入ってくる際(それがユーザーとのインタラクションによるものであれ、WEB APIコールによるものであれ)、そのデータはActionにパッケージされる(実体としては、新しいデータフィールドとアクションを特定するための種別を持ったオブジェクトリテラルで表される)。我々はしばしAction Creatorと呼ばれるヘルパーメソッドのライブラリを作成し、それによってアクションオブジェクトを生成し、それをDispatcherに引き渡す。
Actionはアクションを識別するためのタイプ属性を持つ。StoreはActionを受け取ると通常はこのタイプ属性を用いてそのアクションに対応すべきか否かを判断する。Fluxアプリケーションにおいて、StoreとViewは外部のオブジェクトによって作用されない。Storeはsetterメソッドではなく、自身がDispacherに登録したコールバックによってのみActionを受け取る。
Storeの変更経路をそれ自身によるものに限定することで、MVCでよく見られる込み入った問題(モデル間のカスケード更新が状態の取り扱いを不安定にし、テストを難しくしている)を解消する。Fluxアプリケーションにおいてオブジェクト同士は疎結合であり、デメテルの法則(オブジェクト同士は極力お互いについての知識を持たないようにするという原則)に非常に忠実である。そうすることで、ソフトウェアは保守性と適用性が高く、テストしやすく、またたとえ新しいメンバーがチームに参加しても理解がしやすいものとなる。
Dispatcherはなぜ必要か?
アプリケーションが成長するにつれて、確実にStore間の依存関係が発生する。例えば、Store Aが自分自身を更新するために、Store Bの状態を確認しなければならない、というような状況である。この場合、我々はDispacherが最初にStore Bのコールバックを呼び出し、その処理が完了してから、Store Aのコールバックに移る必要がある。この依存関係を宣言的に扱うために、Store AはDispacherに対して、このActionについてはStore Bの処理が終わるまで待つ必要がある、と伝えることができなければならない。そのため、DispacherはwaitForメソッドを通じてその機能を提供する。
dispatchメソッドは相互に呼び出しあうコールバックを通じてシンプルで同期的なイテレーションを提供する。あるコールバックの中でwaitFor()が用いられた場合、そのコールバックの実行は停止し、waitFor()は我々に新しい依存性のイテレーションサイクルを提供する。全ての依存性が満たされてはじめて、元のコールバックの処理を再開する。
さらに、waitFor()メソッドは同一のStoreのコールバックの異なるアクションに対して様々な方法で用いられるだろう。例えば、あるケースにおいて、Store AがStore Bを待たなければならないとする。しかし、別のケースでは、StoreCを待たなければならないかもしれない。特定のアクションに対してのコードブロックの中でwatiFor()を用いることで、依存関係をコントロールしやすくなる。
しかしながら、循環依存状態を作ってしまうと問題が発生する。つまり、Store AがStore Bならず、同時にStore BがStore Aを待たなければならない、というような状況になると無限ループしてしまう。現在、FluxリポジトリのDispacherはこのような問題が発生した場合に、開発者に知らせるようになっており、その問題を適切に解消することができる。