FluxもMVCも不要?コンポーネント指向Webプログラミング
(※2016/07追記: redux使ってみたら悪くなかったので宗旨替えしました。こちらの記事とかをどうぞ。http://qiita.com/uryyyyyyy/items/7d4b0ede3f2b973d6951 )
タイトルは半分くらい釣りですが、半分くらい本気です。
目的
Fluxわからん
Facebook公式の例の図を見て、「うっ、複雑だ。。。」って受け付けなかった人は僕だけじゃないと思ってます。
そのわりにはメリットもピンとこないし実装も乱立していて、正直『MVC』『オブジェクト指向』のようにバズワード化してる印象を受けています。
そのうち、「やっぱりお前らのFluxは間違ってる」とか、「お前の言うFluxはどこのFluxだよ」とか言い出すんじゃないかと思ってます。
そもそもFluxとかMVC要らなくね?
また、「ReactはViewしか提供しない」という意見がありますが、個人的にはそれで十分だと感じました。(こちらに書きました。React.jsはMVCのVじゃない。フレームワークだ。)
なので、FluxやMVCありきではなく、まずは普通にReactだけで設計をしてみようじゃないか。そこで挙がる問題点と解決策を考えてみようじゃないか。
というところを意図しています。
僕はFluxの知識もないし、クライアントサイドの開発も経験も少ないので、
「こういうケースもあるよね」
「この設計じゃここで死ぬよね」
「それ亜流Fluxなんじゃね?」
などなどご指摘いただけると嬉しいです。
※ 以下、使わない用語
- Flux
- MVVM
- ReactivePrograming
- (WebのURLを用いた)Routing
先に結論
- Fluxとか考えなくても問題なさそう。
- クライアントサイドはView(DOM・それの動的な操作)が全て。
- 業務ロジックとして独立させられるならそうしてもいい。
一般的なWebアプリの構成
超簡略化するとこう。
-
親は子を知って(依存して)いて、子は親を知らない。
- 子コンポーネントは再利用できるようになる。
-
同じ子を複数の親が知ることはない。
- これによって、複雑な画面においても依存関係がシンプルに保たれる。
-
親から子にデータを渡す。
- データのフローが統一されます。
コンポーネントという単語が曖昧ですが、Webアプリにおいては、DOM・振る舞い・データを持った何かです。
静的なHTMLであっても、DOMツリーは親子関係を持ってます。
form要素の中に書いた各valueが、submitボタンでpostされるとか、子から親にイベントがバブリングしていくとか。
以下、こういった設計を『親子コンポーネント指向』と呼んでおきます。
Webアプリの設計≒『親子コンポーネント指向』
古くからあるjQueryPluginなどを見てても、そのコンポーネント自身で独立してます。
必要な値があれば勝手にajaxで取ってくるとか、イベントが欲しければこのAPIからどうぞとか。
以前はMVCの時代があったようなのですが、最近は軒並み方向転換している印象です。
Angular 2系では、controllerやscopeを廃止して、Directive中心になると聞いています。MVCをなくしてコンポーネント間のやりとりだけにしようということかなと。
また、Facebookは「MVCはスケールしない」と言ってReactを開発してます。
また、WebComponentやRiot.js、Vue.jsあたりもHTMLの拡張なので『親子コンポーネント指向』といっていいでしょう。
Webでの『親子コンポーネント指向』においての問題
-
DOMの更新が重たい
- 画面(DOM)の更新は重たいのでなるべくしたくない。
- かといって更新が遅れると、内部状態とDOMで不整合が生じる。
- それらを上手いこと調整しようとすると一気に複雑化する。
-
DOMを操作しにくい。
- WebにおいてHTMLは静的な振る舞いだけで、動的な振る舞いを表すにはJSを使う必要がある。
- jQueryは黒魔術的で設計がぶっ壊れる恐れが。。
- (これの解決にHTMLを拡張させたのがGoogle系・JSを拡張させたのがFacebook系という認識です。。)
「LogicがDOM操作と密結合するのでは」という声に対しては、分離できるのなら汎用関数として抜き出せばいいし、分離できないのならViewの一部なんだと考えればいいと思う。
「Modelの扱いはどうするんだ」という声に対しては、そもそもModelを一元的に管理するとMVC時代に逆戻りするのでダメです。
(個人的にはModelもバズワードで意味が色々あるので使いたくないです。各コンポーネントが知るべき知るべき範囲のデータだけを状態として保持する形が理想だと思います。)
Reactの登場
以上の問題をReactはこう解決しました。
DOMの更新が重たい→仮想DOM
仮想DOMのメリットは、色々な人が言及しているように、「DOMの描画コストを考えなくていい」ことです。
具体的に言えば、「DOMの差分だけを変更することで、ほとんどの場合においてパフォーマンスを損ねることなく、最新の状態に応じた画面を0から生成できる。」とかでしょうか。
その結果、内部状態の管理も、各所でバラバラにデータを持つ必要がなく最新のデータのみを扱えば良いのでシンプルになります。
DOMを操作しにくい→仮想DOM・jsx
jsxという記法によって、JS側でわかりやすくDOMを扱うことができるようになりました。もちろん動的な差し替えも簡単です。
仮想DOMとリアルDOMの違いを意識することすらないでしょう。
その他、状態やイベントの扱い
問題として挙げてたところ以外は、上述の『親子コンポーネント指向』の考え方そのままです。
子は親に依存せず、親は子にデータを渡し、子は親へイベントをバブリングします。
(Reactが、props・stateというデータの扱い方を定めたのも個人的には大きいのですが、それはReactでなくてもできたことかなと。)
設計例
本当にReact + 『親子コンポーネント指向』だけで十分か、使いにくくないかを検討してみます。
それなりに複雑なチケット管理画面を例に取ります。
画面構成
1 GlobalなOverview
2 チケット一覧のOverview
3 チケットTitleをフィルタする文字列を入れるTextForm
4 チケットTitleのフィルタ後のList
5 チケット詳細のOverview
6 チケットのTitleのTextForm
7 チケットのAuthorのSelectBox
8 関連チケット一覧のOverview
9 関連チケットのTableList
10 関連チケットの追加Button
11 チケット詳細の保存Button
仕様(イベント一覧)
- 画面表示時に、ajaxで取得したチケット一覧が④に表示される。
- 画面表示時に、ajaxで取得したユーザー一覧が⑦に格納される。
- ③に文字を入れると、チケットのTitleをフィルタした結果を④に表示する。
- ④の要素一つをクリックすると、⑤にajaxで取得したそのチケットの詳細が表示される。
- チケット詳細に関連チケットがある場合、⑧はajaxでチケットのタイトルを取得し、⑨にそれを表示させる。
- そのチケットに関連チケットがある場合は、そのIDとTitleをajaxで取得して⑨に表示される。
- ⑩を押すと、関連チケットが追加される。(IDはランダムでいいや)
- ⑪を押すと、⑤に入ってる各データをajaxでpostする。
※ajaxの部分はlocalStrageでもファイルでもなんでもいい。
実装例
画面表示時に、ajaxで取得したチケット一覧が④に表示される。
④だけで完結してるイベント。④のコンポーネントがstateとしてチケット一覧を持つ。
画面表示時に、ajaxで取得したユーザー一覧が⑦に格納される。
⑦だけで完結してるイベント。⑦のコンポーネントがstateとしてユーザー一覧を持つ。
③に文字を入れると、チケットのTitleをフィルタした結果を④に表示する。
③に入れた文字列は、②のコンポーネントのstateとして、③と④に渡す。
④はpropsの値によって表示内容を書き換える。
④の要素一つをクリックすると、⑤にajaxで取得したそのチケットの詳細が表示される。
④でどのチケットIDが選ばれたかを①までバブリングする。①は、IDをstateとして持ち、⑤に渡す。
⑤はチケットIDを受け取り、ajax通信を行いチケット詳細を取得し、各データをstateとして保持し、⑥、⑦、⑧にデータを渡す。
⑥はTitleを受け取り、そのままtextformに表示する。
⑦はユーザーIDを受け取り、自身のユーザー一覧と一覧を照らしあわせてマッチするユーザーを表示する。
チケット詳細に関連チケットがある場合、⑧はajaxでチケットのタイトルを取得し、⑨にそれを表示させる。
⑧は関連チケットIDsを受け取り、ajax通信を行いチケットIDとタイトルのペアのデータを取得し、それをstateに持つ。そのペアのリストを⑨に渡す。
⑨は受け取ったペアのリストを表形式で表示する。stateは持たない。
⑩を押すと、関連チケットが追加される。
⑩を押すと、ランダムなチケットIDを含んだイベントが発火し、バブリングする。関連チケットIDsをstateに持つ⑤がそのイベントを処理し、⑧に関連チケットIDsを渡す。
⑪を押すと、⑤に入ってる各データをajaxでpostする。
⑪を押すとsaveイベントが発火し、⑤がそれを受け取って自身のstateのデータをpostする。
図解
つ、疲れた。。。
上記の設計の問題点
複数の階層を跨いでのデータ・イベントのやりとりが厄介
例えば、この図の⑩で発火したイベントを①で扱いたい場合、⑧⑤にもイベントの導線を張らなきゃいけない。(ただ、この手の問題はどんな設計でも遭遇する気がします。)
解決策としては、イベント・データを管理する何かを作り、そいつが複数の階層をまたぐ。平たく言えばグローバル変数みたいなもの。
ただ、そのままでは自由度が高すぎてカオスになるので、「この階層以下だけ」とかのスコープ切りたい。
最後に
Fluxって何が嬉しいのかわからないから誰か教えて。
参考資料
Author And Source
この問題について(FluxもMVCも不要?コンポーネント指向Webプログラミング), 我々は、より多くの情報をここで見つけました https://qiita.com/uryyyyyyy/items/91ad8ecd8192a78513a7著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .