React に対する感情とかコンポーネント管理ライブラリの選定とか
Posted: Updated:
コンポーネント管理できそうなライブラリの選定
ここでいうコンポーネントは HTML 要素をコンポーネントに見立てるような、近代 Web フロントエンドにおける狭義のコンポーネントです。大まかな条件は次の3点。
- コンポーネント中心の開発ができること
- >= IE9 をサポートすること(切っても良さそうなんだけど...)
- 既製品・スクラッチは問わないが極端なリスクは踏めない(納期がシビア)
あとは期待度や API のセンスなど、個人的な審美眼判定に依ります。
- angular/angular : 2.0 が正式リリースしたらまた会いましょう
- jashkenas/backbone : 最近のコンポーネント管理には及ばない
- Custom Elements ( Polymer ) : polyfill が >= IE10サポート
- segmentio/deku : 振る舞いは十分だったけど、>= IE10サポート
- muut/riotjs : 悪くなさそうだったけど、独自プリプロセッサが不安
- facebook/react : みんな使ってるし...
結局 React を採用
様々な葛藤はありましたが、何の面白みもない結論に落ち着いています。
- 今や React の情報は世間に溢れているので「ググれ」が使える
- 業務に耐えうる水準で信頼性が高い(っぽい)
- 対象がPCサイトなので、ファイルサイズには目を瞑れる
- DOM Component の再利用や List まわりのチューニングが優秀(っぽい)
- ECMAScript 6 サポートが順当に行われている
- React 以上に賢い実装をスクラッチする自信とアイディアがない (!)
Flux については FRP ライブラリを組み込んだものを作りましたが、FRP を全メンバーと共有する自信がなかったのでお蔵入り。GitHub にはそのうち公開します。
React の関心と技術の分離にまつわる違和感
React を採用しましたが、その独特の世界観に何の疑問も覚えていないわけではありません。一見してキモさと禁忌しか感じない JSX を肯定する次の一句。
Templates separate technologies, not concerns.
Template は ViewPresenter が提供するデータやメソッドについての知識がなければ記述できず、このような依存関係にあるものを別々にするのは関心の分離ではなく技術の分離に過ぎない。という趣で理解しています。
確かに UI ロジックとテンプレートが近いと嬉しい
Handlebars にせよ AngularJS にせよ、ある変数をループさせるためには、どの変数が Array なのかくらいは知っている必要があります。ループ中に表示の分岐が必要なら、どんなフラグを持った Object が Array の中に入っているのかも知っているはずです。
UI ロジックをもつ ViewPresenter が形ばかり分離された Template とそれ以外の処理の板挟みになって曖昧になっていくのは珍しくありません。そこで ViewPresenter と Template を同一視してまとめたもの(コンポーネント)と、UI 以外の処理に再分類すること自体には一定の納得感があります。
本当に「技術の分離」だったのだろうか
コンテンツやセマンティクスを表現する HTML と、インタラクションや機能を提供する JavaScript は、やはり本来的な関心が異なる要素です。「技術の分離」は UI コンポーネントとしての依存関係に甘んじて、HTML を JavaScript の依り代としてしか見ていないが故の極論のようにも見えます。
後述する Virtual DOM の事情を無視すれば、やはり HTML と JavaScript は分かれて存在しているべきであり、<div className="btn" onClick={foo()}>
よりも <div class="btn js-foo">
が守るべき本来の姿に近いと思えてなりません。JSX で HTML っぽく記述できるだけで、前者の正体は JavaScript です。
HTML には <style>
と <script>
がある
同じファイルの中で見通しを確保するだけであれば Riot 2.0 や vue-component-compiler、Polymer がサポートするような HTML/CSS/JavaScript 混成ファイルになっているだけで解決する問題もあるでしょう。JavaScript に HTML らしきものを書いてメリットがあるのは、関心の問題ではなく技術的な都合が本質だと考えています。
HTML/CSS/JavaScript のうちトリックなしで他の記述言語をファイル内に含められる仕様をもつのは HTML だけであり、HTML が強者であることを忘れてはなりません。
...という下書きをしていましたが、一ヶ月ぶりにみたら「職人が丁寧に書き上げた HTML」vs「JavaScript で生成された HTML」のようにも見えてしまい、結果が同じなら管理対象は「正しい HTML」でも「正しい HTML を生成できる JavaScript」でもどっちでも良いのでは・・・という気持ちもなきにしもあらず。: (
過渡期にある技術としての React
コンポーネントの効率的な管理やアトミックな処理を今すでに使える技術の範疇で表現したかったのであって、HTML や未来の標準仕様を表現したかったわけではなかったはずです。時期的にも Web Components などとの互換性があまり考慮されていなさそうなことには納得しています。
Virtual DOM によって許された怠惰
出尽くしている話ですが、DOM の更新を常に element.innerHTML = template(data)
で済ませたいのは、少なくとも Backbone.js で書いていた頃と変化していません。
この最も怠惰な方法はパフォーマンス上の理由で慎重に扱われてきました。そのため、些細な変更は DOM 操作を手書きしたり、データバインディングによる更新で補助したりしてきました。
ところが Virtual DOM のおかげで、変更規模の大小を問わず element.innerHTML = template(data)
と同じくらい怠惰な方法で DOM を更新できるようになったことは旧来 DOM 職人にとってのメリットです。
HTML テンプレートには荷が重いコンポーネントの差分更新
コンポーネント管理と DOM 要素の差分更新を行いたいとき、これまでの String を生成するだけの HTML テンプレート的なアプローチは JSX + Virtual DOM と比べると大変です。Custom Elements を使わない限り、DOM 要素をコンポーネントとして表現するのは、HTML テンプレートのパースや内部管理の実装で少なくないコストや制約を生み出しがちです。
その点 React は render()
内の Virtual DOM 生成そのものにはあまりコストを払っていません。コンポーネントツリーを HTML テンプレートからあぶり出して抽象オブジェクトを作ったりせず、render()
内で Virtual DOM を生成するメソッドに、コンポーネントのオブジェクトを直接渡すだけという割り切り方です。
ただの JavaScript だからこそ出来る荒技とも言えますが、少なくとも AngularJS のように計算量で頑張るしかなさそうなアプローチよりは効率的です。個人的には、この事情があるからこそ「技術の分離」という言にケチを付けつつも、JSX を Virtual DOM のための必要悪として認めている節があります。
世代交代は訪れるにせよ、触れることに損はなさそう
ここ数年のエッジな JavaScript 業界では、ひとつのライブラリが最有力の座を占めている傾向が強かったように感じられますが、React もいずれは次の最有力に今の地位を譲ることになります。
多くの人が多くの時間と関心を割いて知見を飽和させた React ですから、これまでの最有力たちと同様に当分は使い続けられるでしょうし、次の新しい最有力への乗り換えを強いられない限り、触ってみること自体に損はないと考えています。
アイディアとして生きる Flux や Virtual DOM
React そのものが最有力としての役目を終えても、Angular 2 や Polymer ほか近代的なライブラリが目指している Web フロントエンドのコンポーネント化に少なくない影響を与えそうです。
特に Virtual DOM による DOM 更新の効率化や、イミュータブルなデータフローで状態管理を凝縮する Flux アーキテクチャは、しばらく界隈の開発者の思想として残っていくような気がします。
ポエムでした
ぽえー。