reducer-pipe

1.0.1 • Public • Published

reducer-pipe npm package Travis Coveralls

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 --save

Then 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-chain in 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) => updatedState

Chain:

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) => updatedState

Compare signature

initialize(initialState) => iterator(previousState, currentState) => nextState
  • initialState is corresponding to the state passed to the high order reducer.
  • previousState is corresponding to the previously returned state. Defaults to initialState.
  • currentState is corresponding to the state returned by the reducer at the current index in the list.
  • nextState is corresponding to the state you want to keep.
  • initialize will 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.
  • iterator will be called on each reducer result (passed as currentState). It must compare with previousState (defaults to initialState) 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

  • renum is a small library to create enum using frozen objects in javascript from multiple sources.
  • reducer-chain helps you to chain redux reducers with given state and action, then keep last updated state.
  • reducer-sandbox helps you to reuse your reducers in different place without conflict them.

Package Sidebar

Install

npm i reducer-pipe

Weekly Downloads

0

Version

1.0.1

License

MIT

Last publish

Collaborators

  • bydooweedoo