問題提起
Many people choose to think of React as the V in MVC.
で語られている通り、一般的にはいわゆるViewの部分(仮想DOM)だけを担うライブラリと思われているようです。
「仮想DOMは描画が速いんだ」などと言う人が多くいますが、React.jsによるDOM操作の効率化(差分反映の仕組み)で劇的に改善されるケースってそこまで多くないんじゃないかと思っています。
「じゃぁ、Reactって学習コストに合わなくね?」と僕は思っていましたが、このスライド(React JS and why it's awesome)を見て、実際に学習してみて納得しました。
これはクライアントサイドの設計をひっくり返すフレームワークだと。
何がいいのか?
Reactは以下の機能を持っています。(ざっくり過ぎて意味不明かもしれませんが、機能説明の記事ではないので略します。詳しくは公式サイトで。)
- 片方向データバインディング機構
- (即時)差分レンダリング
- jsxを使った仮想DOMの宣言
- 上位コンポーネントからのデータ(props)はimmutable
これらを使うとどう便利になるかを見ていきます。
HTMLを書く必要がない。
jsxという書式による仮想DOMによって、実質的にHTMLを書く必要がなくなります。
元々HTMLは静的なページを作るためのものだったせいか、近年のWebアプリケーションには時代遅れになっています。
Angularやvue.jsなどではHTMLを独自に拡張していますし、jQuery PluginではSelecterだけ喰わせれば後はライブラリがよろしくやってくれるものが多いです。
PolymerとかElm、Senchaなどに関しては生HTMLをほぼ書かないようになっているので、これは時代の流れなんだろうなと。
コンポーネントを作るだけでいい。
Everything is Component!
MVCなんて要りません。そのコンポーネントがどんな状態を持っていて、どんな振る舞いをすべきかを記述するだけでいいのです。
ボタンや入力フォームはもちろん、ページ全体も一つのコンポーネントとして考えます。
コンポーネントの挙動を宣言的に扱える。
事前にコンポーネントを宣言しておけば、後で生成してあげるだけで適切な挙動をしてくれます。生成後にフローを作る必要はありません。もちろん、DOMの再描画も、必要なときに最適な形でやってくれるので楽です。(俗に言うFRPです。)
これが仮想DOMを使っていない場合は、リアルDOMにmountした後からその対象へのイベント追加などをしてあげなければいけなくて、とても不安定です。
idを指定しなくてもよろしくやってくれる。
個人的な意見なので賛同してもらえるかわかりませんが。。
僕が我流フレームワークを作っていた時も、Polymerなどを参考にして全てをコンポーネント化しようとしていましたが、どのDOMにmountするのかを決めるためにid属性を使おうとすると、idの衝突が起きてしまうケースがあります。(そしてデバッグが厄介です。)
Reactでは、idなど使わなくても親コンポーネントが子コンポーネントを必ず知っているため、一意なidを〜とか考えなくてもいいのです。
データフローが統一される。
Reactでは、子コンポーネントは親コンポーネントから渡されたデータは変更できません。
これによって、各コンポーネントが持つデータ(状態)は、自分しか変更できないため、他のコンポーネントの挙動を考慮する必要がなくなりシンプルな設計になります。
イベントのフローも統一される。
コンポーネント化していく場合には当たり前ですが、子は親のことを知りません。
事前に定義しているインターフェース(this.props)が受け取る値だけを扱えばよいのです。
子がイベントを発火したとき、そのイベントを子だけで処理できない場合は親へ投げられます。(HTMLでもバブリングという仕組みがありますね。)
親に子のデータを渡したい場合はこのイベントの引数として渡してあげます。
(これらの統一されたフローのことをFluxと呼んでいるようです。
公式サイトの図は複雑でよくわかりませんが。。。)
純粋なモデルを扱える。
片方向のデータバインドなので、
- prop/stateの変更を常に反映できる。
- DOMの状態は考慮しないのでモデルは汚されない。
といいとこ取りできます。
(その代わり、単純なサンプルではAngularとかより記述量が増えます。)
単体テストがしやすい
各コンポーネントで閉じている、仮想DOMの状態をReactが管理している、ので原理的にはテストがやりやすいはずです。
が、まだ未検証です。
懸念点
クロスブラウザ対応
たぶんそこらへんはよろしくやってくれてるんだろうと思いますが、特にスマホでちゃんと使えるかとかはよく知りません。
webpack/browserify必須?
コンポーネントを完全に独立させるにはcommonJSスタイルで書く必要があります。
これらをサポートしているモジュール管理ツールが必要です。
テスト/デバッグ
一応ツール群が用意されているものの未検証です。
実行時デバッグは、ほぼJSなので問題なさそうです。
React Componentsがまだまだ不十分
数も多くないし、Demoを載せてくれてるのがあまりない。
個人的には、しばらくはjQuery pluginに頼ることになるかなと思ってます。
(jQuery Pluginへの対応については、componentDidMount
をうまく使うことでなんとかなります。データ変更の親への反映は当然イベントを発火させます。)