redux-nestprops-reducer

1.0.9 • Public • Published

redux-nestprops-reducer v1.0.9

It makes a complex reducer simpler.

If you want to change the disabled flag of a one of the comments of the state below to true,

{
  articles: Map([
    ['Sea', { title: '...', comments: List([{ id: 1, disabled: false  }, { id: 2, disabled: false }]) }],
    ['Sports', { title: '...', comments: List([{ id: 1, disabled: false }, { id: 2, disabled: false }]) }]
  ])
}

define the reducer

const DISABLE = 'DISABLE';
const commentReducer = (state = {}, action) => {
  switch(action.type) {
    case DISABLE:
      return {
        ...state,
        disabled: true,
      };
    default:
      return state;
  }
};

...

combineReducers({
  articles: nestpropsReducer(commentReducer, [ENABLE, DISABLE])(
    (state, action) => state.findKey((v, k) => k === action.category),
    'comments',
    (state, action) => state.findIndex(s => s.id === action.id),
  ),
}),

...
// then dispatch the action
store.dispatch({ type: DISABLE, category: 'Sea', id: 2 });
/*
{
  articles: Map([
    ['Sea', { title: '...', comments: List([{ id: 1, disabled: false  }, { id: 2, disabled: true }]) }],
    ['Sports', { title: '...', comments: List([{ id: 1, disabled: false }, { id: 2, disabled: false }]) }]
  ])
}
*/

Installation

Using npm:

$ npm i --save redux-nestprops-reducer

Usage

import nestpropsReducer, /* optional: { reduceReducers } */ from 'redux-nestprops-reducer';
// var nestpropsReducer = require('redux-nestprops-reducer');
// var reduceReducers = require('redux-nestprops-reducer').reduceReducers;

/**
・whitelist actions are actions of the reducer.
・identifiers can be string, number, or function. The function must return an identifier of the parent object.
*/
const reducer = nestpropsReducer(reducer, [whitelist actions], initialState)(identifiers);

Case: using a reducer for multiple objects.

const nestpropsReducer = require('redux-nestprops-reducer');
const createStore = require('redux').createStore;
const combineReducers = require('redux').combineReducers;

//--- Sample state
const complexState = {
  allArticles: [
    { id: 1, value: 1 },
    { id: 2, value: 2, popular: false },
    { id: 3, value: 3 },
  ],
  popularArticles: [
    { id: 2, value: 2, popular: false },
  ],
};

//--- Sample reducer
const SET_POPULAR = 'SET_POPULAR';
const articleReducer = (state = {}, action) => {
  switch(action.type) {
    case SET_POPULAR:
      return {
        ...state,
        popular: action.popular,
      };
    default:
      return state;
  }
};

const articlesReducer = nestpropsReducer(articleReducer, [SET_POPULAR])
  ((state, action) => state.findIndex(f => f.id === action.id));

const store = createStore(combineReducers({
    allArticles: articleReducer,
    popularArticles: articleReducer,
}), complexState);


const action = { type: SET_POPULAR, id: 2, popular: true };
store.dispatch(action);

console.log(store.getState());
/*
{
  allArticles: [
    { id: 1, value: 1 },
    { id: 2, value: 2, popular: true },
    { id: 3, value: 3 },
  ],
  popularArticlues: [
    { id: 2, value: 2, popular: true },
  ],
};
*/

Case: applying multiple reducers to a same prop

Use reduceReducers

const nestpropsReducer = require('redux-nestprops-reducer');
const reduceReducers = require('redux-nestprops-reducer').reduceReducers;

const complexState = {
  articles: Map([
    ['Sea', { title: '...', comments: List([{ id: 1, disabled: false  }, { id: 2, disabled: false }]) }],
    ['Sports', { title: '...', comments: List([{ id: 1, disabled: false }, { id: 2, disabled: false }]) }],
  ]),
};

const CHANGE_CATEGORY = 'CHANGE_CATEGORY';
const articleReducer = (state = Map(), action) => {
  switch(action.type) {
    case CHANGE_CATEGORY:
      const orig = state.get(action.before);
      return state.remove(action.before).set(action.after, orig);
    default:
      return state;
  }
};

const articlesReducer = nestpropsReducer(commentReducer, [COMMENT_DISABLED]);
const store = createStore(
  combineReducers({
    articles: reduceReducers(
      articleReducer,
      /*
      fooReducer,
      barReducer,
      */
      articlesReducer(
        'Sea',
        'comments',
        (state, action) => state.findIndex(s => s.id === action.id),
      ),
    ),
  }),
  complexState,
);

Case: Handling nested arrays

const complexState = {
  categories: [
    {
      category: 'Sea',
      popularArticlues: [{ id: 2, value: 2, popular: false }],
    },
    {
      category: 'Sports',
      popularArticlues: [{ id: 2, value: 2, popular: false }],
    },
  ]
};

//--- Sample reducer
const SET_POPULAR = 'SET_POPULAR';
const articleReducer = (state = {}, action) => {
  switch(action.type) {
    case SET_POPULAR:
      return {
        ...state,
        popular: action.popular,
      };
    default:
      return state;
  }
};
const articlesReducer = nestpropsReducer(articleReducer, [SET_POPULAR]);

const store = createStore(
  combineReducers({
    categories: articlesReducer(
      (state, action) => state.findIndex(s => s.category === action.category),
      'popularArticlues',
      (state, action) => state.findIndex(s => s.id === action.id)
    ),
  }),
complexState);
const action = { type: SET_POPULAR, category: 'Sports', id: 2, popular: true };
store.dispatch(action);
console.log(store.getState());
/*
{
  categories: [
    {
      category: 'Sea',
      popularArticlues: [{ id: 2, value: 2, popular: false }],
    },
    {
      category: 'Sports',
      popularArticlues: [{ id: 2, value: 2, popular: true }],
    },
  ]
}
*/

// Identifier can be null:
const store = createStore(
  combineReducers({
    categories: articlesReducer(
      null, // null indicates that the list('categories list') may need to be applied an action.
      'popularArticlues',
      (state, action) => state.findIndex(f => f.id === action.id)
    ),
  });
});
const action = { type: SET_POPULAR, category: 'Sports', id: 2, popular: true };
store.dispatch(action);
console.log(store.getState());
/*
{
  categories: [
    {
      category: 'Sea',
      popularArticlues: [{ id: 2, value: 2, popular: true }],
    },
    {
      category: 'Sports',
      popularArticlues: [{ id: 2, value: 2, popular: true }],
    },
  ]
}
*/

Case: Traversing Immutable maps and lists

const complexState = {
  articles: Map([
    ['Sea', { title: '...', comments: List([{ id: 1, disabled: false  }, { id: 2, disabled: false }]) }],
    ['Sports', { title: '...', comments: List([{ id: 1, disabled: false }, { id: 2, disabled: false }]) }],
  ]),
};

const COMMENT_DISABLED = 'COMMENT_DISABLED';
const commentReducer = (state = {}, action) => {
  switch(action.type) {
    case COMMENT_DISABLED:
      return {
        ...state,
        disabled: true,
      };
    default:
      return state;
  }
};

const articlesReducer = nestpropsReducer(commentReducer, [COMMENT_DISABLED]);
const store = createStore(
  combineReducers({
    articles: articlesReducer(
      'Sea',
      'comments',
      (state, action) => state.findIndex(s => s.id === action.id),
    ),
  }),
  complexState,
);
const action = { type: COMMENT_DISABLED, id: 2 };
store.dispatch(action);
console.log(store.getState());
/*
{
  articles: Map([
    ['Sea', { title: '...', comments: List([{ id: 1, disabled: false  }, { id: 2, disabled: true }]) }],
    ['Sports', { title: '...', comments: List([{ id: 1, disabled: false }, { id: 2, disabled: false }]) }],
  ]),
}
*/

Package Sidebar

Install

npm i redux-nestprops-reducer

Weekly Downloads

1

Version

1.0.9

License

ISC

Last publish

Collaborators

  • sndyuk