LoginSignup
1
1

More than 5 years have passed since last update.

LabeledSliderをMVIで書く

Posted at

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")
});
1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1