@@ -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,47 @@ 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
+ const state = store . getState ( )
86
+ const stateProps = this . doStatePropsDependOnOwnProps ?
87
+ this . finalMapStateToProps ( state , props ) :
88
+ this . finalMapStateToProps ( state )
89
+
90
+ return checkStateShape ( stateProps )
91
+ }
92
+
93
+ configureFinalMapState ( store , props ) {
94
+ const mappedState = mapState ( store . getState ( ) , props )
95
+ const isFactory = typeof mappedState === 'function'
96
+ this . finalMapStateToProps = isFactory ? mappedState : mapState
97
+ this . doStatePropsDependOnOwnProps = this . finalMapStateToProps . length !== 1
98
+ return isFactory ? this . computeStateProps ( store , props ) : checkStateShape ( mappedState )
99
+ }
100
+
101
+ computeDispatchProps ( store , props ) {
102
+ if ( ! this . finalMapDispatchToProps ) {
103
+ return this . configureFinalMapDispatch ( store , props )
104
+ }
105
+ const { dispatch } = store
106
+ const dispatchProps = this . doDispatchPropsDependOnOwnProps ?
107
+ this . finalMapDispatchToProps ( dispatch , props ) :
108
+ this . finalMapDispatchToProps ( dispatch )
109
+ return checkStateShape ( dispatchProps , true )
110
+ }
111
+
112
+ configureFinalMapDispatch ( store , props ) {
113
+ const mappedDispatch = mapDispatch ( store . dispatch , props )
114
+ const isFactory = typeof mappedDispatch === 'function'
115
+ this . finalMapDispatchToProps = isFactory ? mappedDispatch : mapDispatch
116
+ this . doDispatchPropsDependOnOwnProps = this . finalMapDispatchToProps . length !== 1
117
+ return isFactory ? this . computeDispatchProps ( store , props ) : checkStateShape ( mappedDispatch , true )
118
+ }
119
+
99
120
updateStatePropsIfNeeded ( ) {
100
- const nextStateProps = computeStateProps ( this . store , this . props )
121
+ const nextStateProps = this . computeStateProps ( this . store , this . props )
101
122
if ( this . stateProps && shallowEqual ( nextStateProps , this . stateProps ) ) {
102
123
return false
103
124
}
@@ -107,7 +128,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
107
128
}
108
129
109
130
updateDispatchPropsIfNeeded ( ) {
110
- const nextDispatchProps = computeDispatchProps ( this . store , this . props )
131
+ const nextDispatchProps = this . computeDispatchProps ( this . store , this . props )
111
132
if ( this . dispatchProps && shallowEqual ( nextDispatchProps , this . dispatchProps ) ) {
112
133
return false
113
134
}
@@ -116,12 +137,14 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
116
137
return true
117
138
}
118
139
119
- updateMergedProps ( ) {
120
- this . mergedProps = computeMergedProps (
121
- this . stateProps ,
122
- this . dispatchProps ,
123
- this . props
124
- )
140
+ updateMergedPropsIfNeeded ( ) {
141
+ const nextMergedProps = computeMergedProps ( this . stateProps , this . dispatchProps , this . props )
142
+ if ( this . mergedProps && checkMergedEquals && shallowEqual ( nextMergedProps , this . mergedProps ) ) {
143
+ return false
144
+ }
145
+
146
+ this . mergedProps = nextMergedProps
147
+ return true
125
148
}
126
149
127
150
isSubscribed ( ) {
@@ -164,6 +187,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
164
187
this . haveOwnPropsChanged = true
165
188
this . hasStoreStateChanged = true
166
189
this . renderedElement = null
190
+ this . finalMapDispatchToProps = null
191
+ this . finalMapStateToProps = null
167
192
}
168
193
169
194
handleChange ( ) {
@@ -203,10 +228,10 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
203
228
let shouldUpdateDispatchProps = true
204
229
if ( pure && renderedElement ) {
205
230
shouldUpdateStateProps = hasStoreStateChanged || (
206
- haveOwnPropsChanged && doStatePropsDependOnOwnProps
231
+ haveOwnPropsChanged && this . doStatePropsDependOnOwnProps
207
232
)
208
233
shouldUpdateDispatchProps =
209
- haveOwnPropsChanged && doDispatchPropsDependOnOwnProps
234
+ haveOwnPropsChanged && this . doDispatchPropsDependOnOwnProps
210
235
}
211
236
212
237
let haveStatePropsChanged = false
@@ -224,7 +249,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
224
249
haveDispatchPropsChanged ||
225
250
haveOwnPropsChanged
226
251
) {
227
- this . updateMergedProps ( )
252
+ haveMergedPropsChanged = this . updateMergedPropsIfNeeded ( )
228
253
} else {
229
254
haveMergedPropsChanged = false
230
255
}
0 commit comments