Skip to content

Instantly share code, notes, and snippets.

@lewtds
Last active May 21, 2016 16:18
Show Gist options
  • Save lewtds/9b5e5c7e6fd7258d2ebc4e5eb453b205 to your computer and use it in GitHub Desktop.
Save lewtds/9b5e5c7e6fd7258d2ebc4e5eb453b205 to your computer and use it in GitHub Desktop.
// @flow
import React from 'react';
import { Updater, view as viewWrapper } from 'redux-elm';
import { takeEvery, takeLatest } from 'redux-saga';
import { call, put, fork, cancel, take, race } from 'redux-saga/effects';
import run from './boilerplate';
type State = {
count: number,
running: boolean,
};
function initialState(): State {
return {
count: 10,
running: false
};
}
const updater = new Updater(initialState(), worker)
.case('START_TIMER', handle_start)
.case('TIMER_STOPPED', handle_stop)
.case('UP', handle_up)
.case('DOWN', handle_down)
.toReducer();
function handle_start(model) {
return {...model, running: true};
}
function handle_stop(model) {
return {...model, running: false};
}
function handle_up(model: State): State {
return {...model, count: model.count + 1};
}
function handle_down(model: State): State {
return {...model, count: model.count - 1};
}
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
function* runTimer() {
while (true) {
yield call(delay, 500);
yield put({type: 'UP'});
}
}
function* worker() {
while (true) {
// take = blockingly wait for the specified event
yield take('START_TIMER');
// once the first task of the two finishes, the other task will be canceled.
yield race({
timerTask: call(runTimer),
cancel: take('STOP_TIMER'),
});
yield put({type: 'TIMER_STOPPED'});
}
}
const startButton = (dispatch) =>
<button onClick={dispatch.bind(null, {type: 'START_TIMER'})}>START</button>;
const stopButton = (dispatch) =>
<button onClick={dispatch.bind(null, {type: 'STOP_TIMER'})}>STOP</button>;
const view = viewWrapper(({model: {count, running}, dispatch}) => {
return (
<div>
{(running ? stopButton : startButton)(dispatch)}
{count}
</div>
);
});
run('app', view, updater);
import React from 'react';
import { render } from 'react-dom';
import { createStore, compose } from 'redux';
import { Provider, connect } from 'react-redux';
import reduxElm from 'redux-elm';
export default (containerDomId, View, updater) => {
const storeFactory = compose(
reduxElm,
window.devToolsExtension ? window.devToolsExtension() : f => f
)(createStore);
const store = storeFactory(updater);
const ConnectedView = connect(appState => ({
model: appState
}))(View);
render((
<Provider store={store}>
<ConnectedView />
</Provider>
), document.getElementById(containerDomId));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment