0.0.4 • Published 7 years ago

redux-scoped-reducer v0.0.4

Weekly downloads
7
License
MIT
Repository
github
Last release
7 years ago

redux-scoped-reducer

build status npm version

Quickstart

Install the library

$ npm install redux-scoped-reducer --save

Basic Usage

// Import the library
import createReducerScope from 'redux-scoped-reducer';
// Create the reducer scoper
const createViewsReducer = createReducerScope('user.views');

// Some view reducer
function viewReducer(state, action) {
  // state here will be scoped to `user.views`
  if (action.type === 'INCREMENT_VIEWS') {
    return {
      ...state,
      viewCount: state.viewCount + 1,
    };
  }
  return state;
}

// Scope the viewReducer function
const scopedViewReducer = reducerScope(viewReducer);

const state = {
  user: {
    views: {
      viewCount: 0,
    }
  },
  // ... other pieces of state
};
const action = {type: 'INCREMENT_VIEWS'};
const nextState = scopedViewReducer(state, action);
// {
//   user: {
//     views: {
//       viewCount: 1,
//     }
//   }
// }

API

import createReducerScope from 'redux-scoped-reducer';

// scope can be dot separated to allow for deep path scoping.
// Examples: 'user', 'user.views', 'user.views.viewCount', ...etc
type createReducerScope = (scope: string) => ReducerCreator;

type ReducerCreator = (Reducer) => Reducer;

// Standard redux reducers and actions.
// Type definitions included for completeness, but nothing special going on here
type Reducer = (state: any, action: Action) => any;
type Action = {
  type: string,
  payload: any,
};

More Usage Examples

import createReducerScope from 'redux-scoped-reducer';
// The scoped reducer pattern works nicely with the `reduce-reducers` library
import reduceReducers from 'reduce-reducers';

const createViewsReducer = createReducerScope('user.views');
const createCounterReducer = createReducerScope('counter');

function viewReducer(state, action) {
  if (action.type === 'INCREMENT_VIEWS') {
    return {
      ...state,
      viewCount: state.viewCount + 1,
    };
  }
  return state;
}

function counterReducer(state, action) {
  if (action.type === 'INCREMENT_COUNTER') {
    return state + 1;
  }
  return state;
}

const scopedViewReducer = createViewsReducer(viewReducer);
const scopedCounterReducer = createCounterReducer(counterReducer);
// scoped reducers can be easily composed using reduce reducers
const rootReducer = reduceReducers(scopedViewReducer, scopedCounterReducer);

let lastState = {
  user: {
    views: {
      viewCount: 0,
    },
    meta: {
      firstName: 'hello',
      lastName: 'world',
    }
  },
  counter: 0,
};

const incrementCounterAction = {type: 'INCREMENT_COUNTER'};
const incrementViewCountAction = {type: 'INCREMENT_VIEWS'};

let nextState = rootReducer(lastState, incrementCounterAction);

// Reference equality at root will be broken
nextState !== lastState

// Reference equality is maintained outside of the changed path
nextState.user === lastState.user

lastState = nextState;
nextState = rootReducer(nextState, incrementViewCountAction);

// Reference equality at root will be broken
nextState !== lastState

// Reference equality is broken within the changed property path
nextState.user !== lastState.user
nextState.user.views !== lastState.user.views

// Reference equality is maintained outside the changed property path,
// even at properties adjacent to ones in the changed path
nextState.user.meta === lastState.user.meta
0.0.4

7 years ago

0.0.3

7 years ago

0.0.2

7 years ago

0.0.1

7 years ago