1
- import React , { Component } from 'react'
1
+ import React , { Component , createElement } from 'react'
2
2
import storeShape from '../utils/storeShape'
3
3
import shallowEqual from '../utils/shallowEqual'
4
4
import isPlainObject from '../utils/isPlainObject'
@@ -28,16 +28,16 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
28
28
wrapActionCreators ( mapDispatchToProps ) :
29
29
mapDispatchToProps || defaultMapDispatchToProps
30
30
const finalMergeProps = mergeProps || defaultMergeProps
31
- const shouldUpdateStateProps = finalMapStateToProps . length !== 1
32
- const shouldUpdateDispatchProps = finalMapDispatchToProps . length !== 1
31
+ const doStatePropsDependOnOwnProps = finalMapStateToProps . length !== 1
32
+ const doDispatchPropsDependOnOwnProps = finalMapDispatchToProps . length !== 1
33
33
const { pure = true , withRef = false } = options
34
34
35
35
// Helps track hot reloading.
36
36
const version = nextVersion ++
37
37
38
38
function computeStateProps ( store , props ) {
39
39
const state = store . getState ( )
40
- const stateProps = shouldUpdateStateProps ?
40
+ const stateProps = doStatePropsDependOnOwnProps ?
41
41
finalMapStateToProps ( state , props ) :
42
42
finalMapStateToProps ( state )
43
43
@@ -51,7 +51,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
51
51
52
52
function computeDispatchProps ( store , props ) {
53
53
const { dispatch } = store
54
- const dispatchProps = shouldUpdateDispatchProps ?
54
+ const dispatchProps = doDispatchPropsDependOnOwnProps ?
55
55
finalMapDispatchToProps ( dispatch , props ) :
56
56
finalMapDispatchToProps ( dispatch )
57
57
@@ -63,7 +63,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
63
63
return dispatchProps
64
64
}
65
65
66
- function computeNextState ( stateProps , dispatchProps , parentProps ) {
66
+ function computeMergedProps ( stateProps , dispatchProps , parentProps ) {
67
67
const mergedProps = finalMergeProps ( stateProps , dispatchProps , parentProps )
68
68
invariant (
69
69
isPlainObject ( mergedProps ) ,
@@ -75,33 +75,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
75
75
76
76
return function wrapWithConnect ( WrappedComponent ) {
77
77
class Connect extends Component {
78
- shouldComponentUpdate ( nextProps , nextState ) {
79
- if ( ! pure ) {
80
- this . updateStateProps ( nextProps )
81
- this . updateDispatchProps ( nextProps )
82
- this . updateState ( nextProps )
83
- return true
84
- }
85
-
86
- const storeChanged = nextState . storeState !== this . state . storeState
87
- const propsChanged = ! shallowEqual ( nextProps , this . props )
88
- let mapStateProducedChange = false
89
- let dispatchPropsChanged = false
90
-
91
- if ( storeChanged || ( propsChanged && shouldUpdateStateProps ) ) {
92
- mapStateProducedChange = this . updateStateProps ( nextProps )
93
- }
94
-
95
- if ( propsChanged && shouldUpdateDispatchProps ) {
96
- dispatchPropsChanged = this . updateDispatchProps ( nextProps )
97
- }
98
-
99
- if ( propsChanged || mapStateProducedChange || dispatchPropsChanged ) {
100
- this . updateState ( nextProps )
101
- return true
102
- }
103
-
104
- return false
78
+ shouldComponentUpdate ( ) {
79
+ return ! pure || this . haveOwnPropsChanged || this . hasStoreStateChanged
105
80
}
106
81
107
82
constructor ( props , context ) {
@@ -116,42 +91,37 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
116
91
`or explicitly pass "store" as a prop to "${ this . constructor . displayName } ".`
117
92
)
118
93
119
- this . stateProps = computeStateProps ( this . store , props )
120
- this . dispatchProps = computeDispatchProps ( this . store , props )
121
- this . state = { storeState : this . store . getState ( ) }
122
- this . updateState ( )
94
+ const storeState = this . store . getState ( )
95
+ this . state = { storeState }
96
+ this . clearCache ( )
123
97
}
124
98
125
- computeNextState ( props = this . props ) {
126
- return computeNextState (
127
- this . stateProps ,
128
- this . dispatchProps ,
129
- props
130
- )
131
- }
132
-
133
- updateStateProps ( props = this . props ) {
134
- const nextStateProps = computeStateProps ( this . store , props )
135
- if ( shallowEqual ( nextStateProps , this . stateProps ) ) {
99
+ updateStatePropsIfNeeded ( ) {
100
+ const nextStateProps = computeStateProps ( this . store , this . props )
101
+ if ( this . stateProps && shallowEqual ( nextStateProps , this . stateProps ) ) {
136
102
return false
137
103
}
138
104
139
105
this . stateProps = nextStateProps
140
106
return true
141
107
}
142
108
143
- updateDispatchProps ( props = this . props ) {
144
- const nextDispatchProps = computeDispatchProps ( this . store , props )
145
- if ( shallowEqual ( nextDispatchProps , this . dispatchProps ) ) {
109
+ updateDispatchPropsIfNeeded ( ) {
110
+ const nextDispatchProps = computeDispatchProps ( this . store , this . props )
111
+ if ( this . dispatchProps && shallowEqual ( nextDispatchProps , this . dispatchProps ) ) {
146
112
return false
147
113
}
148
114
149
115
this . dispatchProps = nextDispatchProps
150
116
return true
151
117
}
152
118
153
- updateState ( props = this . props ) {
154
- this . nextState = this . computeNextState ( props )
119
+ updateMergedProps ( ) {
120
+ this . mergedProps = computeMergedProps (
121
+ this . stateProps ,
122
+ this . dispatchProps ,
123
+ this . props
124
+ )
155
125
}
156
126
157
127
isSubscribed ( ) {
@@ -176,18 +146,38 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
176
146
this . trySubscribe ( )
177
147
}
178
148
149
+ componentWillReceiveProps ( nextProps ) {
150
+ if ( ! pure || ! shallowEqual ( nextProps , this . props ) ) {
151
+ this . haveOwnPropsChanged = true
152
+ }
153
+ }
154
+
179
155
componentWillUnmount ( ) {
180
156
this . tryUnsubscribe ( )
157
+ this . clearCache ( )
158
+ }
159
+
160
+ clearCache ( ) {
161
+ this . dispatchProps = null
162
+ this . stateProps = null
163
+ this . mergedProps = null
164
+ this . haveOwnPropsChanged = true
165
+ this . hasStoreStateChanged = true
166
+ this . renderedElement = null
181
167
}
182
168
183
169
handleChange ( ) {
184
170
if ( ! this . unsubscribe ) {
185
171
return
186
172
}
187
173
188
- this . setState ( {
189
- storeState : this . store . getState ( )
190
- } )
174
+ const prevStoreState = this . state . storeState
175
+ const storeState = this . store . getState ( )
176
+
177
+ if ( ! pure || prevStoreState !== storeState ) {
178
+ this . hasStoreStateChanged = true
179
+ this . setState ( { storeState } )
180
+ }
191
181
}
192
182
193
183
getWrappedInstance ( ) {
@@ -200,10 +190,61 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
200
190
}
201
191
202
192
render ( ) {
203
- const ref = withRef ? 'wrappedInstance' : null
204
- return (
205
- < WrappedComponent { ...this . nextState } ref = { ref } />
206
- )
193
+ const {
194
+ haveOwnPropsChanged,
195
+ hasStoreStateChanged,
196
+ renderedElement
197
+ } = this
198
+
199
+ this . haveOwnPropsChanged = false
200
+ this . hasStoreStateChanged = false
201
+
202
+ let shouldUpdateStateProps = true
203
+ let shouldUpdateDispatchProps = true
204
+ if ( pure && renderedElement ) {
205
+ shouldUpdateStateProps = hasStoreStateChanged || (
206
+ haveOwnPropsChanged && doStatePropsDependOnOwnProps
207
+ )
208
+ shouldUpdateDispatchProps =
209
+ haveOwnPropsChanged && doDispatchPropsDependOnOwnProps
210
+ }
211
+
212
+ let haveStatePropsChanged = false
213
+ let haveDispatchPropsChanged = false
214
+ if ( shouldUpdateStateProps ) {
215
+ haveStatePropsChanged = this . updateStatePropsIfNeeded ( )
216
+ }
217
+ if ( shouldUpdateDispatchProps ) {
218
+ haveDispatchPropsChanged = this . updateDispatchPropsIfNeeded ( )
219
+ }
220
+
221
+ let haveMergedPropsChanged = true
222
+ if (
223
+ haveStatePropsChanged ||
224
+ haveDispatchPropsChanged ||
225
+ haveOwnPropsChanged
226
+ ) {
227
+ this . updateMergedProps ( )
228
+ } else {
229
+ haveMergedPropsChanged = false
230
+ }
231
+
232
+ if ( ! haveMergedPropsChanged && renderedElement ) {
233
+ return renderedElement
234
+ }
235
+
236
+ if ( withRef ) {
237
+ this . renderedElement = createElement ( WrappedComponent , {
238
+ ...this . mergedProps ,
239
+ ref : 'wrappedInstance'
240
+ } )
241
+ } else {
242
+ this . renderedElement = createElement ( WrappedComponent ,
243
+ this . mergedProps
244
+ )
245
+ }
246
+
247
+ return this . renderedElement
207
248
}
208
249
}
209
250
@@ -224,12 +265,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
224
265
225
266
// We are hot reloading!
226
267
this . version = version
227
-
228
- // Update the state and bindings.
229
268
this . trySubscribe ( )
230
- this . updateStateProps ( )
231
- this . updateDispatchProps ( )
232
- this . updateState ( )
269
+ this . clearCache ( )
233
270
}
234
271
}
235
272
0 commit comments