Skip to content

Instantly share code, notes, and snippets.

@3den
Forked from anonymous/index.html
Last active April 2, 2016 10:05
Show Gist options
  • Save 3den/4a9e605ac645b90a499dc330421708ff to your computer and use it in GitHub Desktop.
Save 3den/4a9e605ac645b90a499dc330421708ff to your computer and use it in GitHub Desktop.
basic Rx "state$"
// **** Framework *******
function createAction(reducer) {
const subject$ = new Rx.Subject();
return {
dispatch (payload) {
subject$.onNext(payload);
},
stream$: subject$.map((payload) => {
return reducer.bind(reducer, payload);
})
};
}
function createState$(initState, actions=[]) {
const action$ = actions.reduce((stream$, action) => {
return stream$.merge(action.stream$);
}, Rx.Observable);
return action$
.startWith(initState)
.scan(function (state, reducer) {
return reducer(state);
});
}
// **** App *************************
// What is the best way to do this with Rx????
function incrementWithAjaxCall(data) {
// do something fancy, request weird stuff on ajax
// than you can dispatch the action
// this can be an ajax call or anything async
const ajax$ = Rx.Observable.from([data.i]);
ajax$.subscribe(incrementAction.dispatch);
}
const incrementAction = createAction(function(payload=1, state) {
return Object.assign({}, state, {
count: state.count + payload
});
});
const decrementAction = createAction(function(payload=1, state) {
return Object.assign({}, state, {
count: state.count - payload
});
});
const initState = {count: 0};
const state$ = createState$(initState, [
incrementAction,
decrementAction
]);
const bigCount$ = state$
.map((state) => state.count )
.filter((count) => count > 10);
// side effects, could render component instead
const counter = document.getElementById("counter");
// I can filter the state more and subscribe to it
bigCount$.subscribe((count) => {
counter.style.fontSize = count * 2 + 'px';
});
// I can subscribe to the naked state
state$.subscribe((state) => {
counter.innerHTML = state.count;
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/4.1.0/rx.all.compat.js"></script>
</head>
<body>
<h2>Counter: <span id="counter"></span></h2>
<button onclick="incrementWithAjaxCall({i: 10})">Increment</button>
<button onclick="decrementAction.dispatch()">Decrement</button>
</body>
</html>
// This code does the same a mini-framework.js but is more verbose
function projectIncrement() {
return function (state) {
return Object.assign({}, state, {
count: state.count + 1
});
};
}
function projectDecrement() {
return function (state) {
return Object.assign({}, state, {
count: state.count - 1
});
};
}
var initState = { count: 0 };
var increment$ = new Rx.Subject();
var decrement$ = new Rx.Subject();
var state$ = Rx.Observable
.merge(
increment$.map(projectIncrement),
decrement$.map(projectDecrement)
)
.startWith(initState)
.scan(function (state, project) {
console.log('inc1', state, project);
return project(state);
});
state$.subscribe(function (state) {
var counter = document.getElementById("counter");
counter.innerHTML = state.count;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment