UNPKG

astx-redux-util

Version:

Several redux reducer composition utilities.

93 lines (81 loc) 3.8 kB
import identity from 'lodash.identity'; import isFunction from 'lodash.isfunction'; import verify from '../util/verify'; /** * Create a higher-order reducer that conditionally executes one of * the supplied reducerFns, based on the conditionalFn() return * directive. * * The {{book.guide.devGuide}} discusses conditionalReducer() in more detail * (see {{book.guide.conceptConditional}}), and additional examples can * be found in {{book.guide.conceptJoin}} and {{book.guide.fullExample}}. * * @param {conditionalReducerCB} conditionalFn - a callback function * whose return value determines which reducerFn is executed * ... truthy: thenReducerFn(), falsy: elseReducerFn(). * * @param {reducerFn} thenReducerFn - the "wrapped" reducer invoked * when conditionalFn returns truthy. * * @param {reducerFn} [elseReducerFn=identity] - the * optional "wrapped" reducer invoked when conditionalFn returns * falsy. DEFAULT: [identity function](https://lodash.com/docs#identity) * * @param {InitialState} [initialState] - the optional fall-back state * value used during the state initialization boot-strap process. * * @returns {reducerFn} a newly created reducer function (described above). */ export default function conditionalReducer(conditionalFn, thenReducerFn, elseReducerFn=identity, initialState) { // validate params const check = verify.prefix('AstxReduxUtil.conditionalReducer() parameter violation: '); check(conditionalFn, 'conditionalFn argument is required'); check(isFunction(conditionalFn), 'conditionalFn argument is NOT a function'); check(thenReducerFn, 'thenReducerFn argument is required'); check(isFunction(thenReducerFn), 'thenReducerFn argument is NOT a function'); check(isFunction(elseReducerFn), 'elseReducerFn argument is NOT a function'); // expose our new higher-order reducer // NOTE: For more info on he originalReducerState parameter, refer to the Dev Guide {{book.guide.originalReducerState}} return (state=initialState, action, originalReducerState) => { // maintain the originalReducerState as the immutable state // at the time of the start of the reduction process // ... in support of joinReducers() // ... for more info, refer to the Dev Guide {{book.guide.originalReducerState}} if (originalReducerState === undefined) { originalReducerState = state; } // execute either thenReducerFn or elseReducerFn, based on conditionalFn return conditionalFn(state, action, originalReducerState) ? thenReducerFn(state, action, originalReducerState) : elseReducerFn(state, action, originalReducerState); }; } //*** //*** Specification: conditionalReducerCB //*** /** * A callback function (used in {{book.api.conditionalReducer}}) whose * return value determines which reducerFn is executed. * * @callback conditionalReducerCB * * @param {*} state - The current immutable state that is the * reduction target. * * @param {Action} action - The standard redux Action object that * drives the reduction process. * * @param {*} originalReducerState - The immutable state at the time * of the start of the reduction process. * * This is useful in determining whether state has changed within a * series of reductions {{book.api.joinReducers}} ... because each * individual reducer only has visibility of the state within it's own * reduction process. * * Further information can be found in the * {{book.guide.originalReducerState}} discussion of the {{book.guide.devGuide}}. * * @returns {truthy} A truthy value indicating which reducerFn is * executed ... truthy: thenReducerFn(), falsy: elseReducerFn(). */