2015-10-08 Cycle.js と Model-View-Indent をメモする
Cycle.js と Model-View-Intent
Cycle.js 。いろいろと悩み混乱しているのでここまでの理解をメモする。
Cycle.js では MVI (Model-View-Intent) という方針が示されている。これは公式のドキュメントに書かれている。
Intent の現状の理解は次のとおりだ。
Intent は drivers responses から actions をつくる。これは DOM Event や HTTP レスポンスなど drivers からの生の response からユーザーの意図している action に変換する。
たとえば、back button を click するのはユーザーの意図としては back という action をしたい、ということ。コードで表現すると次のようになる。
function intent(responses) {
const { DOM } = responses;
const actions = {
back: DOM.select('button.back').events('click')
};
return actions;
}
responses は { DOM, HTTP }
のような形式で、これは Cycle.run(main, drivers)
の drivers に driver を登録した際のキーに対応している。
Model の現状の理解は次のとおりだ。
Model は状態を管理する。Intent から actions を受け取り state$ を返す。短い……。
例はこんな感じ。
import { Rx } from '@cycle/core';
function weight(actions) {
return actions
.changeWeight
.startWith(70)
.map(weight => ({ weight }));
}
function model(actions) {
const state$ = Rx.Observable.combineLatest(
weight(actions),
(...args) => Object.assign(...args)
);
return state$;
}
正直なところ、かなり迷っている。
(...args) => Object.assign(...args)
でまとめるために .map(weight => ({ weight }))
のように各 props 側にまとめる処理をいれているところとか。
Observable.combineLatest で状態を { ... }
という state に整形してから流すようにしているけど HTTP driver のように必要なときにしか値を流すべきでないもの (null
や {}
を受け取ると死ぬ) に値を流さないようにするのが view の役割でいいのか……とか。
View の現状の理解は次のとおりだ。
View は state$ から driver requests をつくる。driver requests ってのが driver によってまちまちだけど DOM driver なら vtree$ だし HTTP driver なら request$ 。
これを一本の state$ から切り分けるの大丈夫なのかって感じではある。
import { h } from '@cycle/dom';
function DOM(state$) {
return state$.map(({ weight }) => {
return h('div', [
'Weight: ' + weight + 'kg'
]);
});
}
function HTTP(state$) {
return state$
.filter(({ request }) => request) // for null
.map(({ request }) => request);
}
function view(state$) {
return {
DOM: DOM(state$),
HTTP: HTTP(state$)
}
}
HTTP driver を使う際の Model-View の切り分けや状態が謎。
Model や Intent では {...args}
のために { prop }
や { action }
で返させていたのにここでは { driver }
じゃないのも謎。
いろいろ模索している、ということで。