redux-changes

Process changes in redux with path matching

Usage no npm install needed!

<script type="module">
  import reduxChanges from 'https://cdn.skypack.dev/redux-changes';
</script>

README

redux-changes

Process changes in redux with path matching.

Benefits

  • easier to reduce data that depends on multiple values in the redux store
  • reduce only when changes occur, no needless calculations
  • processes all changes within the same reduction preventing breaks normally caused by side effects pattern
  • cleanly decouple reductions based on data that may be affected by multiple actions
  • no need to replicate reductions in several action reducers

Build Status

npm version
Build Status
NPM

Install

npm install --save redux-changes

Usage

import { createStore } from 'redux';
import { handleChanges, enableChangeHandling } from 'redux-changes';

const handler = handleChanges({
  'path.in.state.{id}': (state, change, data) => {...}
});

const store = createStore(enableChangeHandling(reducer, handler), initialState)

handleChange(pathPattern, reducer)

Creates a reducer that runs if a change is detected in the state at the given path pattern.

handleChange('counter', (state, change, data) => {
  //change = {
  //  path: string,
  //  value: *,
  //  prevValue: *,
  //  state: {current redux state},
  //  prevState: {previous redux state}
  //}
});

handleChanges(handlerMap)

Creates multiple reducers using handleChange() and combines them into a single handler that handles multiple changes. Accepts a map where the keys are passed as the first parameter to handleChange() (the change path), and the values are passed as the second parameter as the handler.

(Internally, handleChanges() works by applying multiple reducers in sequence using reduce-reducers.)

Example:

import { createStore } from 'redux';
import { handleChanges, enableChangeHandling } from 'redux-changes';
import { handleActions } from 'redux-actions' 

const reducer = handleActions({
  INCREMENT: (state, action) => ({
    counters: {
      ...state.counters,
      [action.payload]: state.counters[action.payload] + 1
    }
  }),

  DECREMENT: (state, action) => ({
    counters: {
      ...state.counters,
      [action.payload]: state.counters[action.payload] - 1
    }
  })
}, { counters: {}, average: 0 });


const handler = handleChanges({
  'counters.{name}': (state, change) => ({
    return {
      ...state,
      average: calculateAverage(state.counters)
    }
  })
});

const store = createStore(enableChangeHandling(reducer, handler), initialState)