virtual-domという、(その名の通り)仮想DOMの生成とdiffを行うシンプルなJavaScriptのライブラリがあります。
GitHubのexampleを見るとわかるのですが、このライブラリのみでも、シンプルな形で動的なビューを実現することができます。
このシンプルさがとても魅力的で、実際に使ってみたのですが、
分かったことをまとめたいと思います。
仮想DOMって?
Reactなどで以前から採用されていて、最近流行している感じの 仮想DOM ですが、
- 重い本物のDOMとは別に、仮想のDOM(ただのJSオブジェクトなので軽い)のツリーを構築する
- 仮想DOMの構築を状態が変更されるたびに行って、前回の仮想DOMとのdiffをとって実DOMに適用する
という形で動的なビューの実現に利用されます。
仮想であるので、ブラウザ上だけではなくサーバーサイドのHTMLレンダリングにも使えます。
例
カウンタの例
- カウンタのview model
counter
を用意する - データを元にビューをレンダリングする処理
render
を記述 - 最初に仮想DOMから実DOMを生成
- 次からは仮想DOMの変更を調べてパッチを当てる
という流れでMV*っぽいシンプルなカウンタを記述してみます。
var h = require('virtual-dom/h');
var diff = require('virtual-dom/diff');
var patch = require('virtual-dom/patch');
var createElement = require('virtual-dom/create-element');
// ビューをアップデート
function update() {
var newTree = render(counter);
var patches = diff(tree, newTree);
patch(node, patches);
tree = newTree;
}
// 仮想DOMを生成(レンダリング)
function render(counter) {
return h('div', [
h('p', String(counter.value)),
h('button', {onclick: function () { counter.increment(); }}, 'Increment')
]);
}
var counter = {
value: 0,
increment: function () {
this.value += 1;
update();
}
};
var tree = render(counter);
var node = createElement(tree);
document.body.appendChild(node);
使い方
virtual-domはnpmからのインストールが前提となっているようなので、Browserifyやwebpack経由でインストールします。
すぐに試したいなら、Browserifyを使ったコードをオンラインですぐ実行できるRequireBinがすごく便利です。
わかったこと
主に Vue.jsやKnockout.jsなど、直接DOMにデータバインドする形のライブラリ・フレームワークとの比較 で書いていきたいと思います。
シンプルでやっていることがわかりやすい
直接DOMにデータバインドするライブラリの実装はブラックボックスになりがちですが、
virtual-domは仮想DOMの生成・比較・適用だけでビュー操作のすべてが表されるので、とても明快です。
virtual-dom自体も小さなライブラリで、すぐにコードを読めてしまいます。
ビューに渡すデータの構造が自由
データバインド系フレームワークだと、データの変更を検知し、他の値に依存した値(computed propertyのような)を追従させるために、
ビューに渡すデータに制約が加わることが多いと思うのですが、(Vue.jsだとJSONとして有効なデータに制限される、Knockout.jsだとko.observable
のような特別な値を使わないといけない、など…)
virtual-domの場合、何かしらの値が変わった時に全ビューを手動更新するだけでよいので、その制限が取り払われるのが便利です。
特に、木構造のような複雑なデータ構造を扱いたい場合、素のJSのデータが扱えるのがすごく有り難くなります。
エラーがわかりやすい
ビューの生成プロセスが、実DOMや複雑なデータバインドの絡まないレンダリング処理に集約されるので、エラーが非常にわかりやすくなるのが嬉しいです。
これは仮想DOM自体の大きな利点だと言われているようです。
サーバーサイドのHTMLレンダリングに似てる?
毎回ビューを生成するという考え方は、サーバーサイドのHTMLテンプレートのレンダリングに似ているので、サーバーサイドの人にとって分かりやすいかもしれません。
JSでビューを記述しないといけない
データバインド系ライブラリの場合、動的なビューの記述はHTML上に宣言的に行うことができるのとは対照的になります。
自由度が高くなる反面、ビューに複雑なロジックが入って来てしまい可読性を保つのが難しくなりそうです。
まとめ
virtual-domを使ってプリミティブな動的ビューを記述するような手法はメジャーな方法とは言いがたいですが、メリットも多くあることがわかりました。
virtual-domのような仮想DOMシステムをベースに色々なものを作ってみるのも面白そうと感じました。(virtual-domをベースに作られたフレームワークのmercuryなどが代表例ですね)