Skip to content

Instantly share code, notes, and snippets.

@henhan
Created September 28, 2016 15:35
Show Gist options
  • Save henhan/c0cc0b8eaa792d8cc77fae745d718a22 to your computer and use it in GitHub Desktop.
Save henhan/c0cc0b8eaa792d8cc77fae745d718a22 to your computer and use it in GitHub Desktop.
History enabling redux reducer decorator
'use strict';
function historyEnable(reducer) {
var initObject = {
past: [],
present: reducer(undefined, {}),
future: []
};
// Return a reducer that handles back, forward, and setting history stops
return function (state, action) {
state = state || initObject;
switch (action.type) {
case 'GO_BACK':
var previousState = state.past[state.past.length - 1];
var newPast = state.past.slice(0, state.past.length - 1);
var newFuture = [state.present].concat(state.future);
return {
past: newPast,
present: previousState,
future: newFuture
};
case 'GO_FORWARD':
return {
past: [].concat(state.past).concat([state.present]),
present: state.future[0],
future: state.future.slice(1)
};
case 'SET_HISTORY_POINT':
return {
past: [].concat(state.past).concat([state.present]),
present: state.present,
future: []
};
default:
// Handle an action without affecting history state
return {
past: state.past,
present: reducer(state.present, action),
future: state.future
};
}
};
}
module.exports = historyEnable;
'use strict';
var redux = require('redux');
var historyEnable = require('./historyEnable.js');
function reducer(state, action) {
state = state === undefined ? 5 : state;
switch (action.type) {
case 'PLUS':
return state + 1;
case 'MINUS':
return state - 1;
default:
return state;
}
}
test('initialization of state should work', function() {
var store = redux.createStore(
historyEnable(reducer)
);
var state = store.getState();
expect(state).toBeDefined();
expect(state.past).toEqual([]);
expect(state.future).toEqual([]);
expect(state.present).toEqual(5);
});
test('setting history point should work', function() {
var store = redux.createStore(
historyEnable(reducer)
);
store.dispatch({
type: 'SET_HISTORY_POINT'
});
var state = store.getState();
expect(state.past).toEqual([5]);
expect(state.future).toEqual([]);
expect(state.present).toEqual(5);
});
test('navigating back should work', function() {
var store = redux.createStore(
historyEnable(reducer)
);
store.dispatch({
type: 'SET_HISTORY_POINT'
});
store.dispatch({
type: 'PLUS'
});
store.dispatch({
type: 'SET_HISTORY_POINT'
});
store.dispatch({
type: 'PLUS'
});
store.dispatch({
type: 'GO_BACK'
});
var state = store.getState();
expect(state.past).toEqual([5]);
expect(state.future).toEqual([7]);
expect(state.present).toEqual(6);
});
test('navigating forward should work', function() {
var store = redux.createStore(
historyEnable(reducer)
);
store.dispatch({
type: 'SET_HISTORY_POINT'
});
store.dispatch({
type: 'PLUS'
});
store.dispatch({
type: 'SET_HISTORY_POINT'
});
store.dispatch({
type: 'PLUS'
});
store.dispatch({
type: 'GO_BACK'
});
store.dispatch({
type: 'GO_FORWARD'
});
var state = store.getState();
expect(state.past).toEqual([5, 6]);
expect(state.future).toEqual([]);
expect(state.present).toEqual(7);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment