From baf9451aad1f56cbdf37796166557041b3b6cff3 Mon Sep 17 00:00:00 2001 From: gcanti Date: Tue, 1 Mar 2016 11:48:59 +0100 Subject: [PATCH] First attempt to tackle @slorber's problem Reference: https://github.com/evancz/elm-architecture-tutorial/issues/50 --- README.md | 1 + examples/compose.js | 17 +++++++----- examples/slorber.js | 63 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 examples/slorber.js diff --git a/README.md b/README.md index 2b435b6..8befc3c 100644 --- a/README.md +++ b/README.md @@ -398,6 +398,7 @@ export default { - [Saga pattern (Withdraw saga)](examples/withdraw-saga.js) - [How to handle optmistic updates (optmistic counter)](examples/optmistic-counter.js) - [How to test events and effects](examples/test-delayed-counter.js) +- [Sébastien Lorber's problem (Reference: https://github.com/evancz/elm-architecture-tutorial/issues/50)](examples/slorber.js) ## Type safety diff --git a/examples/compose.js b/examples/compose.js index 3ac4bb5..f419082 100644 --- a/examples/compose.js +++ b/examples/compose.js @@ -1,15 +1,20 @@ import React from 'react' import { Rx } from 'tom' -const composeStates = (x, y) => { +function composeStates(x, y) { return { model: [x.model, y.model], effect: [x.effect, y.effect] } } + +function isNotNil(x) { + return x !== null && x !== undefined +} + const empty = Rx.Observable.just(null) -const isNotNil = x => x !== null && x !== undefined +// apps as groupoid export default function compose(x, y) { return { init() { @@ -22,12 +27,12 @@ export default function compose(x, y) { ) }, view([mx, my], dispatch) { - const dispatch0 = event => dispatch([event]) - const dispatch1 = event => dispatch([null, event]) + const dispatchx = event => dispatch([event]) + const dispatchy = event => dispatch([null, event]) return (
- {x.view(mx, dispatch0)} - {y.view(my, dispatch1)} + {x.view(mx, dispatchx)} + {y.view(my, dispatchy)}
) }, diff --git a/examples/slorber.js b/examples/slorber.js new file mode 100644 index 0000000..497e00a --- /dev/null +++ b/examples/slorber.js @@ -0,0 +1,63 @@ +import React from 'react' +import compose from './compose' +import counter from './counter' + +const counters = compose(counter, compose(counter, counter)) + +function findEvent(event, predicate) { + if (event) { + if (Array.isArray(event)) { + return findEvent(event[0], predicate) || findEvent(event[1], predicate) + } + if (predicate(event)) { + return event + } + } +} + +function isCounterEvent(event) { + return event === 'INCREMENT_REQUEST' || event === 'DECREMENT_REQUEST' +} + +function composeStates(count, state) { + return { + model: { + count, + counters: state.model + }, + effect: state.effect + } +} + +function getCount(count, event) { + if (event === 'INCREMENT_REQUEST' && count < 3) { + return count + 1 + } + if (event === 'DECREMENT_REQUEST' && count > 0) { + return count - 1 + } + return count +} + +export default { + init() { + return composeStates(0, counters.init()) + }, + update(model, event) { + return composeStates( + getCount(model.count, findEvent(event, isCounterEvent)), + counters.update(model.counters, event) + ) + }, + view(model, dispatch) { + return ( +
+

Count: {model.count}

+ {counters.view(model.counters, dispatch)} +
+ ) + }, + run(effect, event$) { + return counters.run(effect, event$) + } +} \ No newline at end of file