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じゃない。フレームワークだ。](http://qiita.com/uryyyyyyy/items/83d75cf79a9202f36cb5)）


なので、FluxやMVCありきではなく、まずは普通にReactだけで設計をしてみようじゃないか。そこで挙がる問題点と解決策を考えてみようじゃないか。

というところを意図しています。

僕はFluxの知識もないし、クライアントサイドの開発も経験も少ないので、

「こういうケースもあるよね」
「この設計じゃここで死ぬよね」
「それ亜流Fluxなんじゃね？」

などなどご指摘いただけると嬉しいです。



※ 以下、使わない用語

- Flux
- MVVM
- ReactivePrograming
- (WebのURLを用いた)Routing


## 先に結論

- Fluxとか考えなくても問題なさそう。
- クライアントサイドはView（DOM・それの動的な操作）が全て。
- 業務ロジックとして独立させられるならそうしてもいい。

## 一般的なWebアプリの構成

超簡略化するとこう。

![Screenshot from 2015-02-21 18:17:58.png](https://qiita-image-store.s3.amazonaws.com/0/7185/36decc57-d278-19ef-623e-c6d5210fb569.png)


- 親は子を知って（依存して）いて、子は親を知らない。
	- 子コンポーネントは再利用できるようになる。

- 同じ子を複数の親が知ることはない。
	- これによって、複雑な画面においても依存関係がシンプルに保たれる。

- 親から子にデータを渡す。
	- データのフローが統一されます。

コンポーネントという単語が曖昧ですが、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の差分だけを変更することで、ほとんどの場合においてパフォーマンスを損ねることなく、最新の状態に応じた画面を０から生成できる。」とかでしょうか。

その結果、内部状態の管理も、各所でバラバラにデータを持つ必要がなく最新のデータのみを扱えば良いのでシンプルになります。

### DOMを操作しにくい→仮想DOM・jsx

jsxという記法によって、JS側でわかりやすくDOMを扱うことができるようになりました。もちろん動的な差し替えも簡単です。
仮想DOMとリアルDOMの違いを意識することすらないでしょう。

### その他、状態やイベントの扱い

問題として挙げてたところ以外は、上述の『親子コンポーネント指向』の考え方そのままです。

子は親に依存せず、親は子にデータを渡し、子は親へイベントをバブリングします。

（Reactが、props・stateというデータの扱い方を定めたのも個人的には大きいのですが、それはReactでなくてもできたことかなと。）

## 設計例

本当にReact + 『親子コンポーネント指向』だけで十分か、使いにくくないかを検討してみます。


それなりに複雑なチケット管理画面を例に取ります。

### 画面構成

![Screenshot from 2015-02-21 18:35:48.png](https://qiita-image-store.s3.amazonaws.com/0/7185/91e96047-037a-0c64-0758-a004390ab760.png)


１ GlobalなOverview
２ チケット一覧のOverview
３ チケットTitleをフィルタする文字列を入れるTextForm
４ チケットTitleのフィルタ後のList
５ チケット詳細のOverview
６ チケットのTitleのTextForm
７ チケットのAuthorのSelectBox
８ 関連チケット一覧のOverview
９ 関連チケットのTableList
１０ 関連チケットの追加Button
１１ チケット詳細の保存Button


### 仕様（イベント一覧）

1. 画面表示時に、ajaxで取得したチケット一覧が④に表示される。
1. 画面表示時に、ajaxで取得したユーザー一覧が⑦に格納される。
1. ③に文字を入れると、チケットのTitleをフィルタした結果を④に表示する。
1. ④の要素一つをクリックすると、⑤にajaxで取得したそのチケットの詳細が表示される。
1. チケット詳細に関連チケットがある場合、⑧はajaxでチケットのタイトルを取得し、⑨にそれを表示させる。
1. そのチケットに関連チケットがある場合は、そのIDとTitleをajaxで取得して⑨に表示される。
1. ⑩を押すと、関連チケットが追加される。（IDはランダムでいいや）
1. ⑪を押すと、⑤に入ってる各データを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する。


### 図解

つ、疲れた。。。

![Screenshot from 2015-02-21 18:37:48.png](https://qiita-image-store.s3.amazonaws.com/0/7185/77994780-47cc-5808-4282-470f449263d9.png)


## 上記の設計の問題点

### 複数の階層を跨いでのデータ・イベントのやりとりが厄介

例えば、この図の⑩で発火したイベントを①で扱いたい場合、⑧⑤にもイベントの導線を張らなきゃいけない。（ただ、この手の問題はどんな設計でも遭遇する気がします。）

解決策としては、イベント・データを管理する何かを作り、そいつが複数の階層をまたぐ。平たく言えばグローバル変数みたいなもの。
ただ、そのままでは自由度が高すぎてカオスになるので、「この階層以下だけ」とかのスコープ切りたい。

## 最後に

Fluxって何が嬉しいのかわからないから誰か教えて。

## 参考資料

- http://www.slideshare.net/AndrewHull/react-js-and-why-its-awesome
- http://jinjor-labo.hatenablog.com/entry/2013/12/12/225955