2016-02-06 bouzuya/virtual-dom-ssr で promise chain を維持する state container をつくった
bouzuya/virtual-dom-ssr で模索していることと、その過程でつくった promise chain を維持する state container の例を書く。まとまっていない。
現状の bouzuya/virtual-dom-ssr は client / server で処理を共通化できていない。その共通化の方法について検討している。たとえば、昨日 (2016-02-05) の routing で言えば、routing 後の処理やその結果をやりとりする方法に迷っている。やりとりする方法をどうすれば client / server でうまく処理を共通化できるのかで迷っている。
いまの案はすべてを event 化することだ。一例は次の通りだ。
- request を event に変換する
- event を「 state を更新する関数」に変換する
- 変換された「 state を更新する関数」で state を更新する
- 更新された state を Virtual DOM に変換する
- 変換された Virtual DOM を HTML / DOM として描画する
この処理の流れは cyclejs/todomvc-cycle や bouzuya/cycle-gh-tree で採用している。挙げた例はどちらも Cycle.js で実装されたものだ。これらの例では cycle-dom を使って event を RxJS の Observable として受け取る。それらを束ねたり関数に変換して state へ適用する。最後に更新された state を cycle-dom に流すことで描画できる。今回は Cycle.js を使用しないつもりだ。Cycle.js (RxJS) の代わりに EventEmitter を使用して、似たような処理の流れをつくろうとしている。
すべてを event 化する案の問題は request を対応する response に変換しないといけないということだ。この問題は Cycle.js をやめたいと書いた 2016-02-03 に近い。 request から event に変換するのは良いが、きっちりと request に対する response を得ることが難しくなりがちだ。
ひとまず、「 state を更新する関数」と state を扱うための data 構造をつくることにした。 Promise chain を維持する state container だ。
bouzuya/virtual-dom-ssr の property.ts がそうだ。利用例は次のとおりだ。
const property = new Property({ name: 'bouzuya' });
property.update((state) => {
return { name: state.name + '!' };
});
property.update((state) => {
return { name: state.name + '?' };
});
property.value().then((state) => {
console.log(state.name); // 'bouzuya!?'
});
良い構造になったら npm package として切り出してもいいかもしれない。ただ、これは RxJS で簡単に代替できそうだし、似たような構造を普段からよく見ている気がする。
追記: bouzuya/promised-state として切り出した。
一日 EventEmitter でゴリゴリ書いてみた結果、 DOM driver 以外の使用を避けて、副作用も気にしなければ Cycle.js でいいんじゃないかという気がしてきた。これについてはまたそのうちに書くと思う。