Created
January 25, 2016 16:29
-
-
Save milankinen/3a5c6bfba11e6f8fdece to your computer and use it in GitHub Desktop.
fluorine+combinators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from "react" | |
import {Subject, Observable} from "rx" | |
import {render} from "react-dom" | |
import {Combinator} from "react-combinators/rx" | |
import {createDispatcher} from "fluorine-lib" | |
const initialBMI = {weight: 80, height: 180} | |
function BMI(state, action) { | |
state = state || initialBMI | |
return action.type === "SET" ? {...state, [action.key]: action.value} : state | |
} | |
function Model() { | |
const dispatcher = createDispatcher() | |
const model = dispatcher.reduce(BMI).shareReplay() | |
const weight = model.map(m => m.weight).share() | |
const height = model.map(m => m.height).share() | |
const bmi = Observable | |
.combineLatest(weight, height) | |
.map(([w, h]) => Math.round(w / (h * h * 0.0001))) | |
.share() | |
return { | |
weight, height, bmi, | |
setWeight: value => dispatcher.dispatch({type: "SET", key: "weight", value}), | |
setHeight: value => dispatcher.dispatch({type: "SET", key: "height", value}) | |
} | |
} | |
function App() { | |
// and here we can use the same object like any other object | |
const { setHeight, setWeight, height, weight, bmi } = Model() | |
return ( | |
<Combinator> | |
<div> | |
<h1>BMI counter example</h1> | |
{renderSlider("Height", height, setHeight, 100, 240)} | |
{renderSlider("Weight", weight, setWeight, 40, 150)} | |
{/* and here we can embed the observables directly into the JSX */} | |
Your BMI is: <span className="bmi">{bmi}</span> | |
</div> | |
</Combinator> | |
) | |
} | |
function renderSlider(title, value, setValue, min, max) { | |
return ( | |
<div> | |
{title}: {value} <br /> | |
<input type="range" min={min} max={max} value={value} className={title} | |
onChange={e => setValue(e.target.value)} /> | |
</div> | |
) | |
} | |
render(<App />, document.getElementById("app")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@milankinen I've just tried the counter example that I've got on the fluorine repo with a combinator. Simple enough I've just dropped it at the top level, which didn't work, but I'll have to investigate that. Dropping it a level deeper worked and there's no notable performance difference. (Maybe it was just the derp though? :D)
This is a very simple example and I have to check how it holds up against bigger codebases. But dropping the observables directly into the jsx is very freeing, as the
withStore
decorator can be removed completely.Then again the decorator saves the code from doing another breadth search of all nodes - even though that's an implementation detail and probably not inefficient.
But at the end of the day the difference in the example would comes down to usage, which looks probably like this in the end:
vs
The difference is probably crucial when you eliminate as much component state as possible and just use pure functions as components, which is probably a nice use case as well, but which unfortunately can also be solved by using a decorator:
vs
This is now a clear improvement, but still I'm not sure if it's worth the price ^^
I'd love to hear more comments from you on this :)