11import createStoreShape from '../utils/createStoreShape' ;
2- import shallowEqualScalar from '../utils/shallowEqualScalar' ;
32import shallowEqual from '../utils/shallowEqual' ;
43import isPlainObject from '../utils/isPlainObject' ;
54import wrapActionCreators from '../utils/wrapActionCreators' ;
@@ -17,19 +16,6 @@ function getDisplayName(Component) {
1716 return Component . displayName || Component . name || 'Component' ;
1817}
1918
20- function areStatePropsEqual ( stateProps , nextStateProps ) {
21- const isRefEqual = stateProps === nextStateProps ;
22- if (
23- isRefEqual ||
24- typeof stateProps !== 'object' ||
25- typeof nextStateProps !== 'object'
26- ) {
27- return isRefEqual ;
28- }
29-
30- return shallowEqual ( stateProps , nextStateProps ) ;
31- }
32-
3319// Helps track hot reloading.
3420let nextVersion = 0 ;
3521
@@ -48,6 +34,38 @@ export default function createConnect(React) {
4834 // Helps track hot reloading.
4935 const version = nextVersion ++ ;
5036
37+ function computeStateProps ( context ) {
38+ const state = context . store . getState ( ) ;
39+ const stateProps = finalMapStateToProps ( state ) ;
40+ invariant (
41+ isPlainObject ( stateProps ) ,
42+ '`mapStateToProps` must return an object. Instead received %s.' ,
43+ stateProps
44+ ) ;
45+ return stateProps ;
46+ }
47+
48+ function computeDispatchProps ( context ) {
49+ const { dispatch } = context . store ;
50+ const dispatchProps = finalMapDispatchToProps ( dispatch ) ;
51+ invariant (
52+ isPlainObject ( dispatchProps ) ,
53+ '`mapDispatchToProps` must return an object. Instead received %s.' ,
54+ dispatchProps
55+ ) ;
56+ return dispatchProps ;
57+ }
58+
59+ function computeNextState ( stateProps , dispatchProps , parentProps ) {
60+ const mergedProps = finalMergeProps ( stateProps , dispatchProps , parentProps ) ;
61+ invariant (
62+ isPlainObject ( mergedProps ) ,
63+ '`mergeProps` must return an object. Instead received %s.' ,
64+ mergedProps
65+ ) ;
66+ return mergedProps ;
67+ }
68+
5169 return DecoratedComponent => class Connect extends Component {
5270 static displayName = `Connect(${ getDisplayName ( DecoratedComponent ) } )` ;
5371 static DecoratedComponent = DecoratedComponent ;
@@ -57,20 +75,52 @@ export default function createConnect(React) {
5775 } ;
5876
5977 shouldComponentUpdate ( nextProps , nextState ) {
60- return (
61- this . isSubscribed ( ) &&
62- ! areStatePropsEqual ( this . state . stateProps , nextState . stateProps )
63- ) || ! shallowEqualScalar ( this . props , nextProps ) ;
78+ return ! shallowEqual ( this . state , nextState ) ;
6479 }
6580
6681 constructor ( props , context ) {
6782 super ( props , context ) ;
6883 this . version = version ;
6984 this . setUnderlyingRef = ::this . setUnderlyingRef ;
70- this . state = {
71- ...this . mapState ( props , context ) ,
72- ...this . mapDispatch ( context )
73- } ;
85+
86+ this . stateProps = computeStateProps ( context ) ;
87+ this . dispatchProps = computeDispatchProps ( context ) ;
88+ this . state = this . computeNextState ( ) ;
89+ }
90+
91+ recomputeStateProps ( ) {
92+ const nextStateProps = computeStateProps ( this . context ) ;
93+ if ( shallowEqual ( nextStateProps , this . stateProps ) ) {
94+ return false ;
95+ }
96+
97+ this . stateProps = nextStateProps ;
98+ return true ;
99+ }
100+
101+ recomputeDispatchProps ( ) {
102+ const nextDispatchProps = computeDispatchProps ( this . context ) ;
103+ if ( shallowEqual ( nextDispatchProps , this . dispatchProps ) ) {
104+ return false ;
105+ }
106+
107+ this . dispatchProps = nextDispatchProps ;
108+ return true ;
109+ }
110+
111+ computeNextState ( props = this . props ) {
112+ return computeNextState (
113+ this . stateProps ,
114+ this . dispatchProps ,
115+ props
116+ ) ;
117+ }
118+
119+ recomputeState ( props = this . props ) {
120+ const nextState = this . computeNextState ( props ) ;
121+ if ( ! shallowEqual ( nextState , this . state ) ) {
122+ this . setState ( nextState ) ;
123+ }
74124 }
75125
76126 isSubscribed ( ) {
@@ -85,7 +135,7 @@ export default function createConnect(React) {
85135 }
86136
87137 tryUnsubscribe ( ) {
88- if ( this . isSubscribed ( ) ) {
138+ if ( this . unsubscribe ) {
89139 this . unsubscribe ( ) ;
90140 this . unsubscribe = null ;
91141 }
@@ -106,61 +156,26 @@ export default function createConnect(React) {
106156
107157 // Update the state and bindings.
108158 this . trySubscribe ( ) ;
109- this . setState ( {
110- ...this . mapState ( ) ,
111- ...this . mapDispatch ( )
112- } ) ;
159+ this . recomputeStateProps ( ) ;
160+ this . recomputeDispatchProps ( ) ;
161+ this . recomputeState ( ) ;
113162 }
114163 }
115164
116- componentWillUnmount ( ) {
117- this . tryUnsubscribe ( ) ;
118- }
119-
120- handleChange ( props = this . props ) {
121- const nextState = this . mapState ( props , this . context ) ;
122- if ( ! areStatePropsEqual ( this . state . stateProps , nextState . stateProps ) ) {
123- this . setState ( nextState ) ;
165+ componentWillReceiveProps ( nextProps ) {
166+ if ( ! shallowEqual ( nextProps , this . props ) ) {
167+ this . recomputeState ( nextProps ) ;
124168 }
125169 }
126170
127- mapState ( props = this . props , context = this . context ) {
128- const state = context . store . getState ( ) ;
129- const stateProps = finalMapStateToProps ( state ) ;
130-
131- invariant (
132- isPlainObject ( stateProps ) ,
133- '`mapStateToProps` must return an object. Instead received %s.' ,
134- stateProps
135- ) ;
136-
137- return { stateProps } ;
138- }
139-
140- mapDispatch ( context = this . context ) {
141- const { dispatch } = context . store ;
142- const dispatchProps = finalMapDispatchToProps ( dispatch ) ;
143-
144- invariant (
145- isPlainObject ( dispatchProps ) ,
146- '`mapDispatchToProps` must return an object. Instead received %s.' ,
147- dispatchProps
148- ) ;
149-
150- return { dispatchProps } ;
171+ componentWillUnmount ( ) {
172+ this . tryUnsubscribe ( ) ;
151173 }
152174
153- merge ( props = this . props , state = this . state ) {
154- const { stateProps, dispatchProps } = state ;
155- const merged = finalMergeProps ( stateProps , dispatchProps , props ) ;
156-
157- invariant (
158- isPlainObject ( merged ) ,
159- '`mergeProps` must return an object. Instead received %s.' ,
160- merged
161- ) ;
162-
163- return merged ;
175+ handleChange ( ) {
176+ if ( this . recomputeStateProps ( ) ) {
177+ this . recomputeState ( ) ;
178+ }
164179 }
165180
166181 getUnderlyingRef ( ) {
@@ -174,7 +189,7 @@ export default function createConnect(React) {
174189 render ( ) {
175190 return (
176191 < DecoratedComponent ref = { this . setUnderlyingRef }
177- { ...this . merge ( ) } />
192+ { ...this . state } />
178193 ) ;
179194 }
180195 } ;
0 commit comments