1
1
import createStoreShape from '../utils/createStoreShape' ;
2
- import shallowEqualScalar from '../utils/shallowEqualScalar' ;
3
2
import shallowEqual from '../utils/shallowEqual' ;
4
3
import isPlainObject from '../utils/isPlainObject' ;
5
4
import wrapActionCreators from '../utils/wrapActionCreators' ;
@@ -17,19 +16,6 @@ function getDisplayName(Component) {
17
16
return Component . displayName || Component . name || 'Component' ;
18
17
}
19
18
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
-
33
19
// Helps track hot reloading.
34
20
let nextVersion = 0 ;
35
21
@@ -48,6 +34,38 @@ export default function createConnect(React) {
48
34
// Helps track hot reloading.
49
35
const version = nextVersion ++ ;
50
36
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
+
51
69
return DecoratedComponent => class Connect extends Component {
52
70
static displayName = `Connect(${ getDisplayName ( DecoratedComponent ) } )` ;
53
71
static DecoratedComponent = DecoratedComponent ;
@@ -57,20 +75,52 @@ export default function createConnect(React) {
57
75
} ;
58
76
59
77
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 ) ;
64
79
}
65
80
66
81
constructor ( props , context ) {
67
82
super ( props , context ) ;
68
83
this . version = version ;
69
84
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
+ }
74
124
}
75
125
76
126
isSubscribed ( ) {
@@ -85,7 +135,7 @@ export default function createConnect(React) {
85
135
}
86
136
87
137
tryUnsubscribe ( ) {
88
- if ( this . isSubscribed ( ) ) {
138
+ if ( this . unsubscribe ) {
89
139
this . unsubscribe ( ) ;
90
140
this . unsubscribe = null ;
91
141
}
@@ -106,61 +156,26 @@ export default function createConnect(React) {
106
156
107
157
// Update the state and bindings.
108
158
this . trySubscribe ( ) ;
109
- this . setState ( {
110
- ...this . mapState ( ) ,
111
- ...this . mapDispatch ( )
112
- } ) ;
159
+ this . recomputeStateProps ( ) ;
160
+ this . recomputeDispatchProps ( ) ;
161
+ this . recomputeState ( ) ;
113
162
}
114
163
}
115
164
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 ) ;
124
168
}
125
169
}
126
170
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 ( ) ;
151
173
}
152
174
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
+ }
164
179
}
165
180
166
181
getUnderlyingRef ( ) {
@@ -174,7 +189,7 @@ export default function createConnect(React) {
174
189
render ( ) {
175
190
return (
176
191
< DecoratedComponent ref = { this . setUnderlyingRef }
177
- { ...this . merge ( ) } />
192
+ { ...this . state } />
178
193
) ;
179
194
}
180
195
} ;
0 commit comments