1- import React , { Component } from 'react'
1+ import React , { Component , createElement } from 'react'
22import storeShape from '../utils/storeShape'
33import shallowEqual from '../utils/shallowEqual'
44import isPlainObject from '../utils/isPlainObject'
@@ -28,16 +28,16 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
2828 wrapActionCreators ( mapDispatchToProps ) :
2929 mapDispatchToProps || defaultMapDispatchToProps
3030 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
3333 const { pure = true , withRef = false } = options
3434
3535 // Helps track hot reloading.
3636 const version = nextVersion ++
3737
3838 function computeStateProps ( store , props ) {
3939 const state = store . getState ( )
40- const stateProps = shouldUpdateStateProps ?
40+ const stateProps = doStatePropsDependOnOwnProps ?
4141 finalMapStateToProps ( state , props ) :
4242 finalMapStateToProps ( state )
4343
@@ -51,7 +51,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
5151
5252 function computeDispatchProps ( store , props ) {
5353 const { dispatch } = store
54- const dispatchProps = shouldUpdateDispatchProps ?
54+ const dispatchProps = doDispatchPropsDependOnOwnProps ?
5555 finalMapDispatchToProps ( dispatch , props ) :
5656 finalMapDispatchToProps ( dispatch )
5757
@@ -63,7 +63,7 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
6363 return dispatchProps
6464 }
6565
66- function computeNextState ( stateProps , dispatchProps , parentProps ) {
66+ function computeMergedProps ( stateProps , dispatchProps , parentProps ) {
6767 const mergedProps = finalMergeProps ( stateProps , dispatchProps , parentProps )
6868 invariant (
6969 isPlainObject ( mergedProps ) ,
@@ -75,33 +75,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
7575
7676 return function wrapWithConnect ( WrappedComponent ) {
7777 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
10580 }
10681
10782 constructor ( props , context ) {
@@ -116,42 +91,37 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
11691 `or explicitly pass "store" as a prop to "${ this . constructor . displayName } ".`
11792 )
11893
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 ( )
12397 }
12498
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 ) ) {
136102 return false
137103 }
138104
139105 this . stateProps = nextStateProps
140106 return true
141107 }
142108
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 ) ) {
146112 return false
147113 }
148114
149115 this . dispatchProps = nextDispatchProps
150116 return true
151117 }
152118
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+ )
155125 }
156126
157127 isSubscribed ( ) {
@@ -176,18 +146,38 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
176146 this . trySubscribe ( )
177147 }
178148
149+ componentWillReceiveProps ( nextProps ) {
150+ if ( ! pure || ! shallowEqual ( nextProps , this . props ) ) {
151+ this . haveOwnPropsChanged = true
152+ }
153+ }
154+
179155 componentWillUnmount ( ) {
180156 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
181167 }
182168
183169 handleChange ( ) {
184170 if ( ! this . unsubscribe ) {
185171 return
186172 }
187173
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+ }
191181 }
192182
193183 getWrappedInstance ( ) {
@@ -200,10 +190,61 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
200190 }
201191
202192 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
207248 }
208249 }
209250
@@ -224,12 +265,8 @@ export default function connect(mapStateToProps, mapDispatchToProps, mergeProps,
224265
225266 // We are hot reloading!
226267 this . version = version
227-
228- // Update the state and bindings.
229268 this . trySubscribe ( )
230- this . updateStateProps ( )
231- this . updateDispatchProps ( )
232- this . updateState ( )
269+ this . clearCache ( )
233270 }
234271 }
235272
0 commit comments