@@ -18,51 +18,33 @@ function getDisplayName(WrappedComponent) {
18
18
return WrappedComponent . displayName || WrappedComponent . name || 'Component'
19
19
}
20
20
21
+ function checkStateShape ( stateProps , dispatch ) {
22
+ invariant (
23
+ isPlainObject ( stateProps ) ,
24
+ '`%sToProps` must return an object. Instead received %s.' ,
25
+ dispatch ? 'mapDispatch' : 'mapState' ,
26
+ stateProps
27
+ )
28
+ return stateProps
29
+ }
30
+
21
31
// Helps track hot reloading.
22
32
let nextVersion = 0
23
33
24
34
export default function connect ( mapStateToProps , mapDispatchToProps , mergeProps , options = { } ) {
25
35
const shouldSubscribe = Boolean ( mapStateToProps )
26
- const finalMapStateToProps = mapStateToProps || defaultMapStateToProps
27
- const finalMapDispatchToProps = isPlainObject ( mapDispatchToProps ) ?
36
+ const mapState = mapStateToProps || defaultMapStateToProps
37
+ const mapDispatch = isPlainObject ( mapDispatchToProps ) ?
28
38
wrapActionCreators ( mapDispatchToProps ) :
29
39
mapDispatchToProps || defaultMapDispatchToProps
40
+
30
41
const finalMergeProps = mergeProps || defaultMergeProps
31
- const doStatePropsDependOnOwnProps = finalMapStateToProps . length !== 1
32
- const doDispatchPropsDependOnOwnProps = finalMapDispatchToProps . length !== 1
42
+ const checkMergedEquals = finalMergeProps !== defaultMergeProps
33
43
const { pure = true , withRef = false } = options
34
44
35
45
// Helps track hot reloading.
36
46
const version = nextVersion ++
37
47
38
- function computeStateProps ( store , props ) {
39
- const state = store . getState ( )
40
- const stateProps = doStatePropsDependOnOwnProps ?
41
- finalMapStateToProps ( state , props ) :
42
- finalMapStateToProps ( state )
43
-
44
- invariant (
45
- isPlainObject ( stateProps ) ,
46
- '`mapStateToProps` must return an object. Instead received %s.' ,
47
- stateProps
48
- )
49
- return stateProps
50
- }
51
-
52
- function computeDispatchProps ( store , props ) {
53
- const { dispatch } = store
54
- const dispatchProps = doDispatchPropsDependOnOwnProps ?
55
- finalMapDispatchToProps ( dispatch , props ) :
56
- finalMapDispatchToProps ( dispatch )
57
-
58
- invariant (
59
- isPlainObject ( dispatchProps ) ,
60
- '`mapDispatchToProps` must return an object. Instead received %s.' ,
61
- dispatchProps
62
- )
63
- return dispatchProps
64
- }
65
-
66
48
function computeMergedProps ( stateProps , dispatchProps , parentProps ) {
67
49
const mergedProps = finalMergeProps ( stateProps , dispatchProps , parentProps )
68
50
invariant (
@@ -96,8 +78,58 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
96
78
this . clearCache ( )
97
79
}
98
80
81
+ computeStateProps ( store , props ) {
82
+ if ( ! this . finalMapStateToProps ) {
83
+ return this . configureFinalMapState ( store , props )
84
+ }
85
+
86
+ const state = store . getState ( )
87
+ const stateProps = this . doStatePropsDependOnOwnProps ?
88
+ this . finalMapStateToProps ( state , props ) :
89
+ this . finalMapStateToProps ( state )
90
+
91
+ return checkStateShape ( stateProps )
92
+ }
93
+
94
+ configureFinalMapState ( store , props ) {
95
+ const mappedState = mapState ( store . getState ( ) , props )
96
+ const isFactory = typeof mappedState === 'function'
97
+
98
+ this . finalMapStateToProps = isFactory ? mappedState : mapState
99
+ this . doStatePropsDependOnOwnProps = this . finalMapStateToProps . length !== 1
100
+
101
+ return isFactory ?
102
+ this . computeStateProps ( store , props ) :
103
+ checkStateShape ( mappedState )
104
+ }
105
+
106
+ computeDispatchProps ( store , props ) {
107
+ if ( ! this . finalMapDispatchToProps ) {
108
+ return this . configureFinalMapDispatch ( store , props )
109
+ }
110
+
111
+ const { dispatch } = store
112
+ const dispatchProps = this . doDispatchPropsDependOnOwnProps ?
113
+ this . finalMapDispatchToProps ( dispatch , props ) :
114
+ this . finalMapDispatchToProps ( dispatch )
115
+
116
+ return checkStateShape ( dispatchProps , true )
117
+ }
118
+
119
+ configureFinalMapDispatch ( store , props ) {
120
+ const mappedDispatch = mapDispatch ( store . dispatch , props )
121
+ const isFactory = typeof mappedDispatch === 'function'
122
+
123
+ this . finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch
124
+ this . doDispatchPropsDependOnOwnProps = this . finalMapDispatchToProps . length !== 1
125
+
126
+ return isFactory ?
127
+ this . computeDispatchProps ( store , props ) :
128
+ checkStateShape ( mappedDispatch , true )
129
+ }
130
+
99
131
updateStatePropsIfNeeded ( ) {
100
- const nextStateProps = computeStateProps ( this . store , this . props )
132
+ const nextStateProps = this . computeStateProps ( this . store , this . props )
101
133
if ( this . stateProps && shallowEqual ( nextStateProps , this . stateProps ) ) {
102
134
return false
103
135
}
@@ -107,7 +139,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
107
139
}
108
140
109
141
updateDispatchPropsIfNeeded ( ) {
110
- const nextDispatchProps = computeDispatchProps ( this . store , this . props )
142
+ const nextDispatchProps = this . computeDispatchProps ( this . store , this . props )
111
143
if ( this . dispatchProps && shallowEqual ( nextDispatchProps , this . dispatchProps ) ) {
112
144
return false
113
145
}
@@ -116,12 +148,14 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
116
148
return true
117
149
}
118
150
119
- updateMergedProps ( ) {
120
- this . mergedProps = computeMergedProps (
121
- this . stateProps ,
122
- this . dispatchProps ,
123
- this . props
124
- )
151
+ updateMergedPropsIfNeeded ( ) {
152
+ const nextMergedProps = computeMergedProps ( this . stateProps , this . dispatchProps , this . props )
153
+ if ( this . mergedProps && checkMergedEquals && shallowEqual ( nextMergedProps , this . mergedProps ) ) {
154
+ return false
155
+ }
156
+
157
+ this . mergedProps = nextMergedProps
158
+ return true
125
159
}
126
160
127
161
isSubscribed ( ) {
@@ -164,6 +198,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
164
198
this . haveOwnPropsChanged = true
165
199
this . hasStoreStateChanged = true
166
200
this . renderedElement = null
201
+ this . finalMapDispatchToProps = null
202
+ this . finalMapStateToProps = null
167
203
}
168
204
169
205
handleChange ( ) {
@@ -203,10 +239,10 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
203
239
let shouldUpdateDispatchProps = true
204
240
if ( pure && renderedElement ) {
205
241
shouldUpdateStateProps = hasStoreStateChanged || (
206
- haveOwnPropsChanged && doStatePropsDependOnOwnProps
242
+ haveOwnPropsChanged && this . doStatePropsDependOnOwnProps
207
243
)
208
244
shouldUpdateDispatchProps =
209
- haveOwnPropsChanged && doDispatchPropsDependOnOwnProps
245
+ haveOwnPropsChanged && this . doDispatchPropsDependOnOwnProps
210
246
}
211
247
212
248
let haveStatePropsChanged = false
@@ -224,7 +260,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
224
260
haveDispatchPropsChanged ||
225
261
haveOwnPropsChanged
226
262
) {
227
- this . updateMergedProps ( )
263
+ haveMergedPropsChanged = this . updateMergedPropsIfNeeded ( )
228
264
} else {
229
265
haveMergedPropsChanged = false
230
266
}
0 commit comments