1 | import { ActionTypes } from './createStore';
|
2 | import isPlainObject from 'lodash-es/isPlainObject';
|
3 | import warning from './utils/warning';
|
4 |
|
5 | function getUndefinedStateErrorMessage(key, action) {
|
6 | var actionType = action && action.type;
|
7 | var actionName = actionType && '"' + actionType.toString() + '"' || 'an action';
|
8 |
|
9 | return 'Given action ' + actionName + ', reducer "' + key + '" returned undefined. ' + 'To ignore an action, you must explicitly return the previous state. ' + 'If you want this reducer to hold no value, you can return null instead of undefined.';
|
10 | }
|
11 |
|
12 | function getUnexpectedStateShapeWarningMessage(inputState, reducers, action, unexpectedKeyCache) {
|
13 | var reducerKeys = Object.keys(reducers);
|
14 | var argumentName = action && action.type === ActionTypes.INIT ? 'preloadedState argument passed to createStore' : 'previous state received by the reducer';
|
15 |
|
16 | if (reducerKeys.length === 0) {
|
17 | return 'Store does not have a valid reducer. Make sure the argument passed ' + 'to combineReducers is an object whose values are reducers.';
|
18 | }
|
19 |
|
20 | if (!isPlainObject(inputState)) {
|
21 | return 'The ' + argumentName + ' has unexpected type of "' + {}.toString.call(inputState).match(/\s([a-z|A-Z]+)/)[1] + '". Expected argument to be an object with the following ' + ('keys: "' + reducerKeys.join('", "') + '"');
|
22 | }
|
23 |
|
24 | var unexpectedKeys = Object.keys(inputState).filter(function (key) {
|
25 | return !reducers.hasOwnProperty(key) && !unexpectedKeyCache[key];
|
26 | });
|
27 |
|
28 | unexpectedKeys.forEach(function (key) {
|
29 | unexpectedKeyCache[key] = true;
|
30 | });
|
31 |
|
32 | if (unexpectedKeys.length > 0) {
|
33 | return 'Unexpected ' + (unexpectedKeys.length > 1 ? 'keys' : 'key') + ' ' + ('"' + unexpectedKeys.join('", "') + '" found in ' + argumentName + '. ') + 'Expected to find one of the known reducer keys instead: ' + ('"' + reducerKeys.join('", "') + '". Unexpected keys will be ignored.');
|
34 | }
|
35 | }
|
36 |
|
37 | function assertReducerShape(reducers) {
|
38 | Object.keys(reducers).forEach(function (key) {
|
39 | var reducer = reducers[key];
|
40 | var initialState = reducer(undefined, { type: ActionTypes.INIT });
|
41 |
|
42 | if (typeof initialState === 'undefined') {
|
43 | throw new Error('Reducer "' + key + '" returned undefined during initialization. ' + 'If the state passed to the reducer is undefined, you must ' + 'explicitly return the initial state. The initial state may ' + 'not be undefined. If you don\'t want to set a value for this reducer, ' + 'you can use null instead of undefined.');
|
44 | }
|
45 |
|
46 | var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.');
|
47 | if (typeof reducer(undefined, { type: type }) === 'undefined') {
|
48 | throw new Error('Reducer "' + key + '" returned undefined when probed with a random type. ' + ('Don\'t try to handle ' + ActionTypes.INIT + ' or other actions in "redux/*" ') + 'namespace. They are considered private. Instead, you must return the ' + 'current state for any unknown actions, unless it is undefined, ' + 'in which case you must return the initial state, regardless of the ' + 'action type. The initial state may not be undefined, but can be null.');
|
49 | }
|
50 | });
|
51 | }
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 |
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 |
|
66 |
|
67 |
|
68 |
|
69 | export default function combineReducers(reducers) {
|
70 | var reducerKeys = Object.keys(reducers);
|
71 | var finalReducers = {};
|
72 | for (var i = 0; i < reducerKeys.length; i++) {
|
73 | var key = reducerKeys[i];
|
74 |
|
75 | if (process.env.NODE_ENV !== 'production') {
|
76 | if (typeof reducers[key] === 'undefined') {
|
77 | warning('No reducer provided for key "' + key + '"');
|
78 | }
|
79 | }
|
80 |
|
81 | if (typeof reducers[key] === 'function') {
|
82 | finalReducers[key] = reducers[key];
|
83 | }
|
84 | }
|
85 | var finalReducerKeys = Object.keys(finalReducers);
|
86 |
|
87 | var unexpectedKeyCache = void 0;
|
88 | if (process.env.NODE_ENV !== 'production') {
|
89 | unexpectedKeyCache = {};
|
90 | }
|
91 |
|
92 | var shapeAssertionError = void 0;
|
93 | try {
|
94 | assertReducerShape(finalReducers);
|
95 | } catch (e) {
|
96 | shapeAssertionError = e;
|
97 | }
|
98 |
|
99 | return function combination() {
|
100 | var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
101 | var action = arguments[1];
|
102 |
|
103 | if (shapeAssertionError) {
|
104 | throw shapeAssertionError;
|
105 | }
|
106 |
|
107 | if (process.env.NODE_ENV !== 'production') {
|
108 | var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
|
109 | if (warningMessage) {
|
110 | warning(warningMessage);
|
111 | }
|
112 | }
|
113 |
|
114 | var hasChanged = false;
|
115 | var nextState = {};
|
116 | for (var _i = 0; _i < finalReducerKeys.length; _i++) {
|
117 | var _key = finalReducerKeys[_i];
|
118 | var reducer = finalReducers[_key];
|
119 | var previousStateForKey = state[_key];
|
120 | var nextStateForKey = reducer(previousStateForKey, action);
|
121 | if (typeof nextStateForKey === 'undefined') {
|
122 | var errorMessage = getUndefinedStateErrorMessage(_key, action);
|
123 | throw new Error(errorMessage);
|
124 | }
|
125 | nextState[_key] = nextStateForKey;
|
126 | hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
|
127 | }
|
128 | return hasChanged ? nextState : state;
|
129 | };
|
130 | } |
\ | No newline at end of file |