Redux, combineReducers and allowing slice reduces to access other parts of the state tree
If you need a redux reducer that adds some "injectables" as the third argument to the reducers normally combined in redux's combineReducers, try this one:
/**
* A combineReducers replacement that adds additional arguments
* to the reduction call to inject different values a reducer
* might need, read-only, from other parts of the tree. Reducer
* order calling is not specified. If no injectables are provided
* the overall state is included under the key "_root_".
*
* @param {Object} reducers Reducer object. Each key with a function is included in a final reducer.
* @param {Object} injectables Key-Functions. All functions are called with the overall state and
* current action. The results are attached to an object under their original keys.
* Non-function values are ignored.
* @param {string} rootName The name of the root that is attached if injectables is empty.
*/
export function combineReducers(reducers, injectables, rootName="_root_") {
const finalReducers = {}
for(var prop in reducers) {
const reducer = reducers[prop]
if(typeof reducer === "function") {
finalReducers[prop] = reducer
}
}
return function composed(state={}, action) {
const finalState = {}
let hasChanged = false
for(var prop in finalReducers) {
const reducer = finalReducers[prop]
const previousState = state[prop]
const nextState = reducer(previousState, action, process(injectables, state, action, rootName))
if(typeof nextState === "undefined") {
throw new Error(`Reducer for key ${prop} returned undefined.`)
}
finalState[prop] = nextState
hasChanged = hasChanged || nextState !== previousState
}
return hasChanged ? finalState : state
}
}
function process(injectables, state, action, rootName) {
const rval = { [rootName]: state }
for(var prop in injectables) {
const func = injectables[prop]
if(typeof func === "function") {
rval[prop] = func(state, action)
}
}
return rval
}
Comments
Post a Comment