Componentsページにサンプルとして紹介されているLabeledSliderを写経し、MVI化してみる。
ドキュメントは理屈重視であまり実践的な書き方が無くてちょっと辛い(Reduxも似た印象だが)。
isolateは全体をdivでラップするだけのようだが、ネストした時どうなるのか要調査。
ex/LabeledSlider.js
import {Observable} from "rx";
import Cycle from "@cycle/core";
import {hJSX} from "@cycle/dom";
function intent(DOM) {
return {
slide$: DOM.select("input[type=range]").events("input").map(ev => ev.target.value)
};
}
function model(props$, actions) {
const initialValue$ = props$.map(props => props.initial).first();
return initialValue$.concat(actions.slide$).map(value => ({value}));
}
function view(props$, state$) {
return Observable.combineLatest(
props$, state$,
(props, state) =>
<div>
<span className="label">{props.label}</span>
<input type="range" min={props.min} max={props.max} value={state.value} />
<span>{state.value}</span>
</div>
);
}
export default function LabeledSliver(drivers) {
const actions = intent(drivers.DOM);
const state$ = model(drivers.props$, actions);
const vtree$ = view(drivers.props$, state$);
return {
DOM: vtree$,
state$
};
}
main.js
import {Observable} from "rx";
import Cycle from "@cycle/core";
import isolate from "@cycle/isolate";
import {makeDOMDriver, hJSX} from "@cycle/dom";
import LabeledSlider from "./ex/LabeledSlider";
function main(drivers) {
const sliderWidth = isolate(LabeledSlider)({
DOM: drivers.DOM,
props$: Observable.of({
label: "Width",
unit: "",
min: 10,
max: 50,
initial: 30
})
});
const sliderHeight = isolate(LabeledSlider)({
DOM: drivers.DOM,
props$: Observable.of({
label: "Height",
unit: "",
min: 10,
max: 50,
initial: 30
})
});
const vtree$ = Observable.combineLatest(
sliderWidth.DOM, sliderWidth.state$,
sliderHeight.DOM, sliderHeight.state$,
(widthVTree, widthState, heightVTree, heightState) =>
<div>
{widthVTree}
{heightVTree}
<div style={{
backgroundColor: "#F88",
width: String(widthState.value) + "px",
height: String(heightState.value) + "px",
}} />
</div>
);
return {
DOM: vtree$
}
}
Cycle.run(main, {
DOM: makeDOMDriver("main")
});