Reduxはわかった。Fluxとはなんなのだ?
React/Reduxは昨今のWebフロントではよく見る構成なので、学んでいる方は多いと思う。
Reduxの関連文献を読むと度々Fluxという言葉が出てくるがあれは一体なんなのか。
この記事では、Reduxとの違いを意識しながらFluxを紐解いていく。
Fluxとはアーキテクチャである
Facebookが生み出したクライアントサイドウェブアプリ用のアーキテクチャである。
Reduxはライブラリの名前であるが、Fluxはアーキテクチャの名前である。つまり特定のライブラリを指す言葉ではない。
(とはいえfacebook/fluxがutilを提供しており、これが使われることが多い)
このアーキテクチャの実装を助けるライブラリが多数生まれたが、その中で一際人気を誇ったのがRedux。
ReduxはFluxのような単一方向のデータパスに基づく設計思想になっているが構成要素に違いがある。
なぜFluxなのか MVCでは難しい実装ケース
ReduxとFluxの話に入る前に、もう一つ有名なアーキテクチャのMVCの話を最初にする。
MVCモデルではどんな時に不都合なのだろうか。
端的に書くとMVCでは1つのデータソースを複数箇所のUIから操作されるようなケースでコードが複雑になる。
公式の例ではチャットの未読数のカウント表示が挙げられている。
- チャットは不特定多数の人から送られ、その内どれかが既読になればカウントを-1する
- 2カ所からチャット開けるならそれぞれの箇所で既読時にカウントを-1するロジックをいれる
- 2カ所に存在するカウント表示にデータの変更を反映させる
このように、共通のデータを複数箇所から変更 & 参照する場合、Viewのデータソースとなる値をどこでどう管理するのかが難しくなる。
MVCでは複数箇所から更新され、複数箇所に対して更新を反映する複雑なデータフローになるところを、Fluxであれば単一で1方向のデータフローで表現することができる。
Fluxの主要素
下記の要素がFluxの主要素と言われている。
- dispatcher
- store
- view
- action
いずれもReduxの経験者であればなんとなく耳にしたことがあるような単語ではあるが、それぞれ少しずつ意味合いが異なる。
dispatcher
storeに対してcallbackを登録し、呼び出しに応じてそれを起動する存在。
Action Creatorメソッドから呼び出され、新しいデータを持ったActionオブジェクトをStoreに伝える役割を持つ。
1つのdispatcherが複数のcallbackを登録することができ、データをブロードキャストすることができる。
store
データを管理するオブジェクト。
getterを持つがsetterは持たず、dispatcherによって登録されたcallbackからのみ更新される。
Reduxとは異なり、storeは複数存在することができる。それぞれのstoreに対してdispatcherはcallbackを登録する。
view
storeのデータを参照して作成されるアプリケーションの見た目の部分。
storeからデータを受け取るviewのことを Controller view と呼び、子孫コンポーネントに対してPropsを渡していく役割を持っている。
viewとController viewに分けることで、viewの責務をシンプルに保つことができる。
Action
Actionはストアを更新する際の新しいデータを含んだオブジェクト。
dispatcherに対してActionを渡す関数をAction Creatorと呼ぶのはReduxと同じだが、FluxではActionsというオブジェクトのメソッドとしてAction Creatorが実装されることが多いらしい。(Flux公式でもAction Creatorはmethodであると書かれている)
Fluxコードを体験してみたいなら
facebookがチュートリアル付きのexampleを提供しているので、Readme.mdに従ってコーディングをしてみるとFluxの書き味が体験できる。
flux-todomvc
TodoMVCをFluxで作っていくチュートリアルで序盤は写経できるサンプルと解説、最後には解答無しの練習課題がついているので良い練習になる。
flux/utilを使用するので書き方はReduxに近いものがあり、Reduxでのアプリ制作経験があるの人ならそれほど時間をかけずに終えられると思う。
(筆者はこの記事を書くにあたってトライした)
Reduxとの違い
上記のFluxの特徴と重複する部分はあるが、Reduxの違いにフォーカスしてまとめる。
dispatcherの存在
ReduxにDispatcherは無い。Store.dispatch()というメソッドはあるが別物。
上記の通り、dispatcherはstoreに対してcallbackを登録する役割を持つ。action creatorからDispatcher.dispatch()がcallされることからfluxの中心的な位置にいると言っていい。
Reduxでは、dispatcherが登録するcallbackの役割をreducerが担っている。
action creatorの役割
dispatcherに関連してaction creatorの動きも少しだけ違う。
fluxのaction creatorはactionを引数にしてdispatcher.dispatchをcallする役割がある。
Reduxにおけるaction creatorは呼ばれた時にactionを返却する。
creatorという名前のイメージにはこちらの方が近い。dispatcherとの結合がなくシンプル。
middlewareが存在しない
Fluxはmiddlewareという仕組みを持たない。Dispatcher.dispatch()はあらかじめ登録したCallbackを呼ぶための処理であり、間に他の処理を挟むことはできない。
ReduxはmiddlewareによってdispatchされたActionをロギングしたり、エラーActionのハンドリングを行うなどReduxの処理フロー全体に影響を与えるような処理を含むことができる。
redux-thunk, redux-observableなどの非同期処理用のmiddlewareを活用することで、非同期処理の責務をらAction Creatorに持たせることができるようになるためComponentをシンプルに作りやすい。
Fluxのstateは複数のstoreによって表現される
Fluxは複数のstoreを持つ。例えばTwitterのようなシステムであればUserInfoStoreとTweetListStoreのようなstoreを持つことになる。
これに対してReduxは1つのplain old Javascript object (POJO)でstateを表現する。アプリケーション全体の状態を扱いたいケースにおいては1つのオブジェクトである方が遥かに扱いやすい。
例えばSSRは、サーバーでstateを構築してクライアントに送信する必要があり単一のオブジェクトである恩恵を受けている。
stateを追加する際にはFluxは新たなstoreを作成し、dispatcherから新たなcallbackを登録する。
Reduxは純粋な関数であるReducerを追加するのみであり、拡張がシンプル。
終わりに
ReduxはFluxを基にして生まれたライブラリというだけあって使い勝手が良い面が多い。
Fluxを用いて新規にアプリケーションを作成する機会は少ないと思うが、アーキテクチャの話題では頻出単語なので正しく理解しておくと役立つと思う。