@@ -5,7 +5,7 @@ import pick from '../utils/pick';
5
5
6
6
/* eslint-disable no-console */
7
7
8
- function getErrorMessage ( key , action ) {
8
+ function getUndefinedStateErrorMessage ( key , action ) {
9
9
var actionType = action && action . type ;
10
10
var actionName = actionType && `"${ actionType . toString ( ) } "` || 'an action' ;
11
11
@@ -15,36 +15,34 @@ function getErrorMessage(key, action) {
15
15
) ;
16
16
}
17
17
18
- function verifyStateShape ( inputState , outputState , action ) {
18
+ function getUnexpectedStateKeyWarningMessage ( inputState , outputState , action ) {
19
19
var reducerKeys = Object . keys ( outputState ) ;
20
20
var argumentName = action && action . type === ActionTypes . INIT ?
21
21
'initialState argument passed to createStore' :
22
22
'previous state received by the reducer' ;
23
23
24
24
if ( reducerKeys . length === 0 ) {
25
- console . error (
25
+ return (
26
26
'Store does not have a valid reducer. Make sure the argument passed ' +
27
27
'to combineReducers is an object whose values are reducers.'
28
28
) ;
29
- return ;
30
29
}
31
30
32
31
if ( ! isPlainObject ( inputState ) ) {
33
- console . error (
32
+ return (
34
33
`The ${ argumentName } has unexpected type of "` +
35
34
( { } ) . toString . call ( inputState ) . match ( / \s ( [ a - z | A - Z ] + ) / ) [ 1 ] +
36
35
`". Expected argument to be an object with the following ` +
37
36
`keys: "${ reducerKeys . join ( '", "' ) } "`
38
37
) ;
39
- return ;
40
38
}
41
39
42
40
var unexpectedKeys = Object . keys ( inputState ) . filter (
43
41
key => reducerKeys . indexOf ( key ) < 0
44
42
) ;
45
43
46
44
if ( unexpectedKeys . length > 0 ) {
47
- console . error (
45
+ return (
48
46
`Unexpected ${ unexpectedKeys . length > 1 ? 'keys' : 'key' } ` +
49
47
`"${ unexpectedKeys . join ( '", "' ) } " found in ${ argumentName } . ` +
50
48
`Expected to find one of the known reducer keys instead: ` +
@@ -53,6 +51,34 @@ function verifyStateShape(inputState, outputState, action) {
53
51
}
54
52
}
55
53
54
+ function assertReducerSanity ( reducers ) {
55
+ Object . keys ( reducers ) . forEach ( key => {
56
+ var reducer = reducers [ key ] ;
57
+ var initialState = reducer ( undefined , { type : ActionTypes . INIT } ) ;
58
+
59
+ if ( typeof initialState === 'undefined' ) {
60
+ throw new Error (
61
+ `Reducer "${ key } " returned undefined during initialization. ` +
62
+ `If the state passed to the reducer is undefined, you must ` +
63
+ `explicitly return the initial state. The initial state may ` +
64
+ `not be undefined.`
65
+ ) ;
66
+ }
67
+
68
+ var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math . random ( ) . toString ( 36 ) . substring ( 7 ) . split ( '' ) . join ( '.' ) ;
69
+ if ( typeof reducer ( undefined , { type } ) === 'undefined' ) {
70
+ throw new Error (
71
+ `Reducer "${ key } " returned undefined when probed with a random type. ` +
72
+ `Don't try to handle ${ ActionTypes . INIT } or other actions in "redux/*" ` +
73
+ `namespace. They are considered private. Instead, you must return the ` +
74
+ `current state for any unknown actions, unless it is undefined, ` +
75
+ `in which case you must return the initial state, regardless of the ` +
76
+ `action type. The initial state may not be undefined.`
77
+ ) ;
78
+ }
79
+ } ) ;
80
+ }
81
+
56
82
/**
57
83
* Turns an object whose values are different reducer functions, into a single
58
84
* reducer function. It will call every child reducer, and gather their results
@@ -74,54 +100,33 @@ export default function combineReducers(reducers) {
74
100
var finalReducers = pick ( reducers , ( val ) => typeof val === 'function' ) ;
75
101
var sanityError ;
76
102
77
- Object . keys ( finalReducers ) . forEach ( key => {
78
- var reducer = finalReducers [ key ] ;
79
- var initialState ;
80
-
81
- try {
82
- initialState = reducer ( undefined , { type : ActionTypes . INIT } ) ;
83
- } catch ( e ) {
84
- sanityError = e ;
85
- }
86
-
87
- if ( ! sanityError && typeof initialState === 'undefined' ) {
88
- sanityError = new Error (
89
- `Reducer "${ key } " returned undefined during initialization. ` +
90
- `If the state passed to the reducer is undefined, you must ` +
91
- `explicitly return the initial state. The initial state may ` +
92
- `not be undefined.`
93
- ) ;
94
- }
95
-
96
- var type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math . random ( ) . toString ( 36 ) . substring ( 7 ) . split ( '' ) . join ( '.' ) ;
97
- if ( ! sanityError && typeof reducer ( undefined , { type } ) === 'undefined' ) {
98
- sanityError = new Error (
99
- `Reducer "${ key } " returned undefined when probed with a random type. ` +
100
- `Don't try to handle ${ ActionTypes . INIT } or other actions in "redux/*" ` +
101
- `namespace. They are considered private. Instead, you must return the ` +
102
- `current state for any unknown actions, unless it is undefined, ` +
103
- `in which case you must return the initial state, regardless of the ` +
104
- `action type. The initial state may not be undefined.`
105
- ) ;
106
- }
107
- } ) ;
103
+ try {
104
+ assertReducerSanity ( finalReducers ) ;
105
+ } catch ( e ) {
106
+ sanityError = e ;
107
+ }
108
108
109
109
var defaultState = mapValues ( finalReducers , ( ) => undefined ) ;
110
110
111
111
return function combination ( state = defaultState , action ) {
112
112
if ( sanityError ) {
113
113
throw sanityError ;
114
114
}
115
+
115
116
var finalState = mapValues ( finalReducers , ( reducer , key ) => {
116
117
var newState = reducer ( state [ key ] , action ) ;
117
118
if ( typeof newState === 'undefined' ) {
118
- throw new Error ( getErrorMessage ( key , action ) ) ;
119
+ var errorMessage = getUndefinedStateErrorMessage ( key , action ) ;
120
+ throw new Error ( errorMessage ) ;
119
121
}
120
122
return newState ;
121
123
} ) ;
122
124
123
125
if ( process . env . NODE_ENV !== 'production' ) {
124
- verifyStateShape ( state , finalState , action ) ;
126
+ var warningMessage = getUnexpectedStateKeyWarningMessage ( state , finalState , action ) ;
127
+ if ( warningMessage ) {
128
+ console . error ( warningMessage ) ;
129
+ }
125
130
}
126
131
127
132
return finalState ;
0 commit comments