lore-reducers
v0.13.0
Published
Library to reduce boilerplate for Redux reducers
Downloads
11
Readme
lore-reducers
Installation
Lore Reducers is available as an npm package.
npm install lore-reducers
After npm install, you'll find all the .js files in the /src folder and their compiled versions in the /lib folder.
Usage
lore-reducers is an abstraction teir to reduce the boilerplate associated with created reducers for use with Redux. It provides a set of common reducer functions as well as a blueprint you can use to build reducers.
The blueprint looks like this:
var { utils, blueprint } = require('lore-reducers');
var all = blueprint({
state: 'INITIAL_STATE',
data: []
}, [
{
actionType: types.ADD_TODO,
method: utils.addOrUpdateModel
},{
actionType: types.UPDATE_TODO,
method: utils.updateModel
},{
actionType: types.REMOVE_TODO,
method: utils.removeModel
},{
actionType: types.FETCH_TODO,
method: utils.mergeModels
},{
actionType: types.FETCH_TODOS_IN_LIST,
method: utils.mergeModels
}
]
);
The following common functions are also available within the utils
object. Given a reducer that looks like this:
function(state, action){...}
- addModel: take the action.payload add it to state.data
- updateModel: find the model within state.data that matches action.payload and replace it
- removeModel: find the model within state.data that matches action.payload and remove it
- replaceModels: poorly named, but effectively replaces the current state with action.payload
- mergeModels: takes the set of models in action.payload and merges them into state.data (adding or updating each model as applicable)
- copyState: copy action.payload.state and action.payload.error to state.state and state.error respectively
- getIndex: if action.payload is in state.data, returns the index, otherwise returns -1
- addOrUpdateModel: updates the model in state.data if action.payload already exists, otherwise adds it to state.data
- mergeModelsAndCopyState: calls mergeModels and also runs copyState to copy state and error attributes to state
The following functions are also available, which are mean to be used as reducers themselves:
- function byId(state): takes all models in state.data and creates a dictionary from them using their id as the key
- function byCid(state): takes all models in state.data and creates a dictionary from them using their cid as the key
Reasoning for Interface
The thought process behind this was to reduce boilerplate while being extensible, and providing an interface that was generic enough to adapt to the wide array of (often changing) reducer needs on the client side.
The central logic of a reducer is a case statement that says "if the action.type matches X, apply this reducing function to the state". With that in mind, the only unique about a reducer is the ActionType it's listening for and the method it should apply to state. So that's why those are the two arguments in the object.
Additionally, this interface can also let you pass in custom functions aren't in the utils helpers in order to accomodate custom application needs.
Another design goal was to create an interface that could easily be generated by a series of conventions.
The actionType
follows the pattern of MethodName_ModelName
, and in most cases MethodName
(add, update, remove) maps to a common function (addModel, updateModel, removeModel). So if a framework created a set of conventions for the ActionTypes, and made sure they were consistent between the Actions and Reducers, many of the reducers could be reduced to an empty config files, similar to the magic that Sails applies to Models and Controllers which both start off as empty objects.