Skip to content

Instantly share code, notes, and snippets.

@miyucy
Created August 8, 2016 00:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save miyucy/6bd90005a407a531efd47dc376961f65 to your computer and use it in GitHub Desktop.
Save miyucy/6bd90005a407a531efd47dc376961f65 to your computer and use it in GitHub Desktop.
const actionCreator = () => ({ type: 'SOME_ACTION' });
const noopReducer = (state, action) => state;
const noopEnhancer = (store) => store;
const noopMiddleware = store => next => action => next(action);
export function createStore(reducer = noopReducer, initialState = undefined, enhancer = noopEnhancer) {
let state = initialState;
let listeners = [];
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach((f) => f());
return action;
};
return enhancer({
dispatch,
getState: () => state,
subscribe: (listener) => listeners.push(listener),
unsubscribe: () => listeners = [],
});
}
export function applyMiddleware(...middlewares) {
return (store) => {
let dispatch = store.dispatch;
middlewares.reverse();
middlewares.forEach((middleware) => {
dispatch = middleware(store)(dispatch);
});
return Object.assign({}, store, { dispatch });
};
}
export function combineReducers(reducers) {
return function (state, action) {
return Object.keys(reducers).reduce((newState, key) => {
const reducer = reducers[key];
return Object.assign({}, newState, {
[key]: reducer(state[key], action)
});
}, {});
};
}
export function bindActionCreators(actionCreators, dispatch) {
return Object.keys(actionCreators).reduce((newActionCreators, key) => {
const actionCreator = actionCreators[key];
return Object.assign({}, newActionCreators, {
[key]: (...args) => {
const action = actionCreator(...args);
dispatch(action);
}
});
}, {});
}
import assert from 'assert';
import {
createStore, combineReducers, bindActionCreators, applyMiddleware
} from './redux';
describe('redux', () => {
describe('createStore', () => {
const reducer = (state = 0, action) => {
switch (action.type) {
case 'incr':
return state + 1;
case 'decr':
return state - 1;
case 'Incr':
return state + action.n;
case 'Decr':
return state - action.n;
default:
return state;
};
};
const logger1 = store => next => action => {
console.log('[1] before', action);
const result = next(action);
console.log('[1] after', store.getState());
return result;
};
const logger2 = store => next => action => {
console.log('[2] before', action);
const result = next(action);
console.log('[2] after', store.getState());
return result;
};
it('', () => {
const store = createStore(reducer, 0);
store.subscribe(() => console.log('listener', store.getState()));
store.dispatch({ type: 'incr' });
store.dispatch({ type: 'decr' });
store.unsubscribe();
});
it('', () => {
const store = createStore(reducer, 0, applyMiddleware(logger1, logger2));
store.dispatch({ type: 'Incr', n: 100 });
store.dispatch({ type: 'Decr', n: -50 });
});
});
describe('combineReducers', () => {
const incr = (state = 0, action) => state + 1;
const decr = (state = 0, action) => state - 1;
it('', () => {
const reducer = combineReducers({ incr, decr });
const state = reducer({ incr: 0, decr: 1 }, { type: 'noop' });
assert(state.incr === 1);
assert(state.decr === 0);
});
});
describe('bindActionCreators', () => {
const seq = (a, b, c) => {
return { type: 'action', a, b, c };
};
const inv = (a, b, c) => {
return { type: 'action', x: a, y: b, z: c };
};
const dispatch = (action) => {
console.log(action);
};
it('', () => {
const bounds = bindActionCreators({ seq, inv }, dispatch);
console.log('seq');
seq(1, 2, 3);
console.log('bounds.seq');
bounds.seq(1, 2, 3);
console.log('inv');
inv(1, 2, 3);
console.log('bounds.inv');
bounds.inv(1, 2, 3);
});
});
});
export default (store) => {
return (next) => {
return (action) => {
return (
typeof action === 'function' ?
action(store.dispatch, store.getState)
:
next(action)
);
};
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment