1
1
import hoistStatics from 'hoist-non-react-statics'
2
2
import invariant from 'invariant'
3
- import React , { Component , createElement } from 'react'
3
+ import React , { Component , PureComponent , createElement } from 'react'
4
4
5
5
import { ReactReduxContext } from "./context" ;
6
- import shallowEqual from '../utils/shallowEqual'
7
6
8
7
let hotReloadingVersion = 0
9
- const dummyState = { }
10
- function noop ( ) { }
11
- function makeSelectorStateful ( sourceSelector ) {
12
- // wrap the selector in an object that tracks its results between runs.
13
- const selector = {
14
- run : function runComponentSelector ( props , storeState ) {
15
- try {
16
- const nextProps = sourceSelector ( storeState , props )
17
- if ( nextProps !== selector . props || selector . error ) {
18
- selector . shouldComponentUpdate = true
19
- selector . props = nextProps
20
- selector . error = null
21
- }
22
- } catch ( error ) {
23
- selector . shouldComponentUpdate = true
24
- selector . error = error
25
- }
26
- }
27
- }
28
8
29
- return selector
30
- }
31
9
32
10
export default function connectAdvanced (
33
11
/*
@@ -105,12 +83,13 @@ export default function connectAdvanced(
105
83
}
106
84
107
85
86
+ const OuterBaseComponent = connectOptions . pure ? PureComponent : Component ;
87
+
108
88
class ConnectInner extends Component {
109
89
constructor ( props ) {
110
90
super ( props ) ;
111
91
112
92
this . state = {
113
- storeState : props . storeState ,
114
93
wrapperProps : props . wrapperProps ,
115
94
renderCount : 0 ,
116
95
store : props . store ,
@@ -131,7 +110,7 @@ export default function connectAdvanced(
131
110
132
111
static getChildPropsState ( props , state ) {
133
112
try {
134
- const nextProps = state . childPropsSelector ( state . storeState , props . wrapperProps )
113
+ const nextProps = state . childPropsSelector ( props . storeState , props . wrapperProps )
135
114
if ( nextProps === state . childProps ) return null
136
115
return { childProps : nextProps }
137
116
} catch ( error ) {
@@ -140,20 +119,28 @@ export default function connectAdvanced(
140
119
}
141
120
142
121
static getDerivedStateFromProps ( props , state ) {
143
- if ( ( connectOptions . pure && shallowEqual ( props . wrapperProps , state . wrapperProps ) ) || state . error ) {
122
+ const nextChildProps = ConnectInner . getChildPropsState ( props , state )
123
+
124
+ if ( nextChildProps === null ) {
144
125
return null ;
145
126
}
146
127
147
- const nextChildProps = ConnectInner . getChildPropsState ( props , state )
148
-
149
128
return {
150
129
...nextChildProps ,
151
130
wrapperProps : props . wrapperProps ,
152
131
}
153
132
}
154
133
155
134
shouldComponentUpdate ( nextProps , nextState ) {
156
- return nextState . childProps !== this . state . childProps ;
135
+ const childPropsChanged = nextState . childProps !== this . state . childProps ;
136
+ const storeStateChanged = nextProps . storeState !== this . props . storeState ;
137
+ const hasError = ! ! nextState . error ;
138
+
139
+ let wrapperPropsChanged = false ;
140
+
141
+ const shouldUpdate = childPropsChanged || hasError ;
142
+ return shouldUpdate ;
143
+
157
144
}
158
145
159
146
render ( ) {
@@ -165,75 +152,13 @@ export default function connectAdvanced(
165
152
}
166
153
}
167
154
168
- class Connect extends Component {
155
+ class Connect extends OuterBaseComponent {
169
156
constructor ( props ) {
170
157
super ( props )
171
158
172
- this . version = version
173
- this . renderCount = 0
174
- this . storeState = null ;
175
-
176
-
177
- //this.setWrappedInstance = this.setWrappedInstance.bind(this)
178
159
this . renderInner = this . renderInner . bind ( this ) ;
179
-
180
- // TODO How do we express the invariant of needing a Provider when it's used in render()?
181
- /*
182
- invariant(this.store,
183
- `Could not find "${storeKey}" in either the context or props of ` +
184
- `"${displayName}". Either wrap the root component in a <Provider>, ` +
185
- `or explicitly pass "${storeKey}" as a prop to "${displayName}".`
186
- )
187
- */
188
160
}
189
-
190
- componentDidMount ( ) {
191
- if ( ! shouldHandleStateChanges ) return
192
-
193
- // componentWillMount fires during server side rendering, but componentDidMount and
194
- // componentWillUnmount do not. Because of this, trySubscribe happens during ...didMount.
195
- // Otherwise, unsubscription would never take place during SSR, causing a memory leak.
196
- // To handle the case where a child component may have triggered a state change by
197
- // dispatching an action in its componentWillMount, we have to re-run the select and maybe
198
- // re-render.
199
- this . selector . run ( this . props , this . storeState ) ;
200
- if ( this . selector . shouldComponentUpdate ) this . forceUpdate ( )
201
- }
202
-
203
-
204
- UNSAFE_componentWillReceiveProps ( nextProps ) {
205
- // TODO Do we still want/need to implement sCU / cWRP now?
206
- this . selector . run ( nextProps , this . storeState ) ;
207
- }
208
-
209
- shouldComponentUpdate ( ) {
210
- return this . selector . shouldComponentUpdate
211
- }
212
-
213
-
214
- componentWillUnmount ( ) {
215
- this . selector . run = noop
216
- this . selector . shouldComponentUpdate = false
217
- }
218
-
219
- getWrappedInstance ( ) {
220
- invariant ( withRef ,
221
- `To access the wrapped instance, you need to specify ` +
222
- `{ withRef: true } in the options argument of the ${ methodName } () call.`
223
- )
224
- return this . wrappedInstance
225
- }
226
-
227
- setWrappedInstance ( ref ) {
228
- this . wrappedInstance = ref
229
- }
230
-
231
- initSelector ( dispatch , storeState ) {
232
- const sourceSelector = selectorFactory ( dispatch , selectorFactoryOptions )
233
- this . selector = makeSelectorStateful ( sourceSelector )
234
- this . selector . run ( this . props , storeState ) ;
235
- }
236
-
161
+ /*
237
162
addExtraProps(props) {
238
163
if (!withRef && !renderCountProp) return props;
239
164
@@ -247,37 +172,19 @@ export default function connectAdvanced(
247
172
248
173
return withExtras
249
174
}
175
+ */
250
176
251
177
renderInner ( providerValue ) {
252
178
const { storeState, store} = providerValue ;
253
179
254
- /*
255
- this.storeState = storeState;
256
-
257
- if(this.selector) {
258
- this.selector.run(this.props, storeState);
259
- }
260
- else {
261
- this.initSelector(dispatch, storeState);
262
- }
263
-
264
- if (this.selector.error) {
265
- // TODO This will unmount the whole tree now that we're throwing in render. Good idea?
266
- // TODO Related: https://github.com/reactjs/react-redux/issues/802
267
- throw this.selector.error
268
- }
269
- else if(this.selector.shouldComponentUpdate) {
270
- //console.log(`Re-rendering component (${displayName})`, this.selector.props);
271
- this.selector.shouldComponentUpdate = false;
272
- this.renderedElement = createElement(WrappedComponent, this.addExtraProps(this.selector.props));
273
- }
274
- else {
275
- //console.log(`Returning existing render result (${displayName})`, this.props)
276
- }
277
-
278
- return this.renderedElement;
279
- */
280
- return < ConnectInner storeState = { storeState } store = { store } wrapperProps = { this . props } />
180
+ return (
181
+ < ConnectInner
182
+ key = { this . version }
183
+ storeState = { storeState }
184
+ store = { store }
185
+ wrapperProps = { this . props }
186
+ />
187
+ ) ;
281
188
}
282
189
283
190
render ( ) {
@@ -291,8 +198,8 @@ export default function connectAdvanced(
291
198
292
199
Connect . WrappedComponent = WrappedComponent
293
200
Connect . displayName = displayName
201
+
294
202
// TODO We're losing the ability to add a store as a prop. Not sure there's anything we can do about that.
295
- //Connect.propTypes = contextTypes
296
203
297
204
// TODO With connect no longer managing subscriptions, I _think_ is is all unneeded
298
205
/*
0 commit comments