reducer-pipe
v1.0.1
Published
Allows to pipe redux reducers with given state and action, passing previously returned state to next reducer, then keep last updated state.
Maintainers
Readme
reducer-pipe

reducer-pipe helps you to pipe redux reducers with given state and action, passing previously returned state to next reducer, then keep last updated state.
Getting started
Install reducer-pipe using npm:
npm install reducer-pipe --saveThen using ES6
import { increment, decrement } from './my-reducers';
import reducerPipe from 'reducer-pipe';
export default reducerPipe([
increment,
decrement,
]);Using ES5
var myReducers = require('./my-reducers');
var reducerPipe = require('reducer-pipe');
module.exports = reducerPipe([
myReducers.increment,
myReducers.decrement,
]);Usage
You can rewrite this:
const reducer = (state, action) => {
if (!state) state = initialState;
switch (action.type) {
case 'ADD':
case 'INCREMENT':
return incrementReducer(state, action);
case 'SUBTRACT':
case 'DECREMENT':
return decrementReducer(state, action);
default:
return state;
}
};
reducer({counter: 0}, {type: 'INCREMENT'}); //=> {counter: 1}To this:
import reducerPipe from 'reducer-pipe';
const reducer = reducerPipe([
(state/*, action*/) => (state ? state : initialState),
incrementReducer,
decrementReducer,
]);
reducer({counter: 0}, {type: 'INCREMENT'}); //=> {counter: 1}See also
reducer-chainin order to chain given reducers with same given state and action.
Examples
Explanation
Take this code:
const reducer = reducerPipe([
initial, // returns initial state if given state is null, else returns given state
increment, // increments counter in state copy if action is INCREMENT, else returns given state
decrement, // decrements counter in state copy if action is DECREMENT, else returns given state
]);When we call:
reducer(null, {type: 'INCREMENT'}); // default compare set to `reducerPipe.compare.withInitial`It will execute:
// We pass given state and action to our first reducer in list, which is `initial`
initial(null, {type: 'INCREMENT'}) //=> returns initial state {counter: 0}
compare(null, {counter: 0}) //=> Previous state is null, returns {counter: 0}
// now we will pass previously returned state by compare
increment({counter: 0}, {type: 'INCREMENT'}) //=> Increment counter by 1, returns {counter: 1}
compare({counter: 0}, {counter: 1}) //=> Current state differs from previous, returns {counter: 1}
// now we will pass previously returned state by compare
decrement({counter: 1}, {type: 'INCREMENT'}) //=> Nothing happens, returns given state {counter: 1}
compare({counter: 1}, {counter: 1}) //=> Both state are the same object, returns {counter: 1}Pipe:
reducer(state, action) => updatedState
initial(state, action) => newState
compare(state, newState) => newState
increment(newState, action) => updatedState
compare(newState, updatedState) => updatedState
decrement(updatedState, action) => updatedState
compare(updatedState, updatedState) => updatedStateChain:
reducer(state, action) => updatedState
initial(state, action) => newState
increment(state, action) => updatedState
decrement(state, action) => state
compare(state, newState) => newState
compare(newState, updatedState) => updatedState
compare(updatedState, state) => updatedStateCompare signature
initialize(initialState) => iterator(previousState, currentState) => nextStateinitialStateis corresponding to the state passed to the high order reducer.previousStateis corresponding to the previously returned state. Defaults toinitialState.currentStateis corresponding to the state returned by the reducer at the current index in the list.nextStateis corresponding to the state you want to keep.initializewill be called everytime once with the given state from the high order reducer. It must returns an iterator function for comparing previous and current state, and return the prefered one.iteratorwill be called on each reducer result (passed ascurrentState). It must compare withpreviousState(defaults toinitialState) and return the state you want to keep next.
Note: Please note that initiaze is called before calling any reducer.
Then reducer are called one by one in given order, and iterator is called after each reducer.
Available compare functions
reducer-pipe built in with 4 different compare functions available under reducerPipe.compare:
| Name | Signature | Equals |
| ---- | --------- | ------ |
| withInitial (default) | (initialState) => (previousState, currentState) => nextState | R.equals(initialState, currentState) |
| withInitialCustomEquals | (customEquals) => (initialState) => (previousState, currentState) => nextState | customEquals(initialState, currentState) |
| withPrevious | (initialState) => (previousState, currentState) => nextState | R.equals(previousState, currentState) |
| withPreviousCustomEquals | (customEquals) => (initialState) => (previousState, currentState) => nextState | customEquals(previousState, currentState) |
Compare usage
With immutable:
// ./immutableReducerPipe.js
import Immutable from 'immutable';
import reducerPipe from 'reducer-pipe';
export default reducerPipe(
reducerPipe.compare.withPreviousCustomEquals(Immutable.is)
);// ./index.js
import Immutable from 'immutable';
import { reducer1, reducer2 } from './reducers';
import immutableReducerPipe from './immutableReducerPipe';
const initialState = Immutable.Map({counter: 0});
export default immutableReducerPipe([
(state/*, action*/) => (state ? state : initialState),
reducer1,
reducer2,
]);With custom compare:
import reducerPipe from 'reducer-pipe';
import {reducer1, reducer2} from './reducers';
const customCompare = initialState => (previousState, currentState) => (
currentState !== null &&
currentState !== initialState ?
currentState : previousState
);
const initialState = Object.freeze({counter: 0});
export default reducerPipe(customCompare, [
(state/*, action*/) => (state ? state : initialState),
reducer1,
reducer2,
]);Links
renumis a small library to create enum using frozen objects in javascript from multiple sources.reducer-chainhelps you to chainreduxreducers with given state and action, then keep last updated state.reducer-sandboxhelps you to reuse your reducers in different place without conflict them.
