UNPKG

3.7 kBJavaScriptView Raw
1import identity from 'lodash.identity';
2import isFunction from 'lodash.isfunction';
3import verify from '../util/verify';
4
5/**
6 * Create a higher-order reducer by combining a set of sub-reducer
7 * functions that are indexed by the standard action.type. When no
8 * action.type is acted on, the original state is merely
9 * passed-through (using the [identity
10 * function](https://lodash.com/docs#identity)).
11 *
12 * This is one of the more prevalent composition reducers, and
13 * provides an alternative to the switch statement (commonly used to
14 * provide this control mechanism).
15 *
16 * The {{book.guide.devGuide}} discusses reducerHash() in more detail (see
17 * {{book.guide.conceptHash}}), and additional examples can be found in
18 * {{book.guide.conceptJoin}} and {{book.guide.fullExample}}.
19 *
20 * **SideBar**: Because reducerHash is so central to the rudimentary
21 * aspect of reduction, it is a common practice to extend it,
22 * promoting a
23 * [`centralized reducer-based logging capability`](/extending/logExt.md),
24 * with an ability to correlate logging levels to state changes
25 * *(providing a means to filter logs at a high level with minimal
26 * output)*.
27 *
28 * @param {ActionReducerHash} actionHandlers - a hash of reducer functions,
29 * indexed by the standard redux action.type.
30 *
31 * @param {InitialState} [initialState] - the optional fall-back state
32 * value used during the state initialization boot-strap process.
33 *
34 * @returns {reducerFn} a newly created reducer function (described above).
35 */
36export default function reducerHash(actionHandlers, initialState) {
37
38 // validate params
39 const check = verify.prefix('AstxReduxUtil.reducerHash() parameter violation: ');
40
41 check(actionHandlers,
42 'actionHandlers is required');
43
44 // ... AI: this check may be too intrusive if the client's actionHandlers object is used for OTHER things?
45 const invalidHashEntry = Object.getOwnPropertyNames(actionHandlers).reduce( (firstBadEntry, type) => {
46 return firstBadEntry || isFunction(actionHandlers[type]) ? null : type;
47 }, null);
48 check(!invalidHashEntry,
49 `actionHandlers['${invalidHashEntry}'] is NOT a function ... expecting reducer function indexed by action type`);
50
51 check(!actionHandlers['undefined'],
52 "actionHandlers contains an 'undefined' entry ... suspect a misspelled constant");
53
54
55 // internal function: locate handler from actionHandlers action.type hash lookup
56 // ... default: identity pass-through
57 const locateHandler = (action) => actionHandlers[action.type] || identity;
58
59 // expose the new reducer fn, which resolves according the the supplied actionHandlers
60 return (state=initialState, action, originalReducerState) => {
61
62 // maintain the originalReducerState as the immutable state
63 // at the time of the start of the reduction process
64 // ... in support of joinReducers()
65 // ... for more info, refer to the Dev Guide {{book.guide.originalReducerState}}
66 if (originalReducerState === undefined) {
67 originalReducerState = state;
68 }
69
70 // execute the handler indexed by the action.type (or the identity pass-through)
71 return locateHandler(action)(state, action, originalReducerState);
72 };
73}
74
75
76//***
77//*** Specification: ActionReducerHash
78//***
79
80/**
81 * @typedef {Object} ActionReducerHash
82 *
83 * A hash of reducer functions, indexed by the standard redux
84 * action.type.
85 *
86 * @property {reducerFn} actionType1 - The reducer function servicing: 'actionType1'.
87 * @property {reducerFn} actionType2 - The reducer function servicing: 'actionType2'.
88 * @property {reducerFn} ...more - ...etc.
89 */