Skip to content

Commit 48a34b0

Browse files
committed
Revert connect and provider to v5.0.7's versions
1 parent f3836e2 commit 48a34b0

File tree

2 files changed

+59
-53
lines changed

2 files changed

+59
-53
lines changed

src/components/Provider.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ export function createProvider(storeKey = 'store') {
3838
}
3939

4040
if (process.env.NODE_ENV !== 'production') {
41-
Provider.prototype.componentDidUpdate = function () {
42-
if (this[storeKey] !== this.props.store) {
41+
Provider.prototype.componentWillReceiveProps = function (nextProps) {
42+
if (this[storeKey] !== nextProps.store) {
4343
warnAboutReceivingStore()
4444
}
4545
}

src/components/connectAdvanced.js

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
11
import hoistStatics from 'hoist-non-react-statics'
22
import invariant from 'invariant'
33
import { Component, createElement } from 'react'
4-
import { polyfill } from 'react-lifecycles-compat'
54

65
import Subscription from '../utils/Subscription'
76
import { storeShape, subscriptionShape } from '../utils/PropTypes'
87

98
let hotReloadingVersion = 0
9+
const dummyState = {}
1010
function noop() {}
11-
function makeUpdater(sourceSelector, store) {
12-
return function updater(props, prevState) {
13-
try {
14-
const nextProps = sourceSelector(store.getState(), props)
15-
if (nextProps !== prevState.props || prevState.error) {
16-
return {
17-
shouldComponentUpdate: true,
18-
props: nextProps,
19-
error: null,
11+
function makeSelectorStateful(sourceSelector, store) {
12+
// wrap the selector in an object that tracks its results between runs.
13+
const selector = {
14+
run: function runComponentSelector(props) {
15+
try {
16+
const nextProps = sourceSelector(store.getState(), props)
17+
if (nextProps !== selector.props || selector.error) {
18+
selector.shouldComponentUpdate = true
19+
selector.props = nextProps
20+
selector.error = null
2021
}
21-
}
22-
return {
23-
shouldComponentUpdate: false,
24-
}
25-
} catch (error) {
26-
return {
27-
shouldComponentUpdate: true,
28-
error,
22+
} catch (error) {
23+
selector.shouldComponentUpdate = true
24+
selector.error = error
2925
}
3026
}
3127
}
28+
29+
return selector
3230
}
3331

3432
export default function connectAdvanced(
@@ -88,10 +86,6 @@ export default function connectAdvanced(
8886
[subscriptionKey]: subscriptionShape,
8987
}
9088

91-
function getDerivedStateFromProps(nextProps, prevState) {
92-
return prevState.updater(nextProps, prevState)
93-
}
94-
9589
return function wrapWithConnect(WrappedComponent) {
9690
invariant(
9791
typeof WrappedComponent == 'function',
@@ -123,6 +117,7 @@ export default function connectAdvanced(
123117
super(props, context)
124118

125119
this.version = version
120+
this.state = {}
126121
this.renderCount = 0
127122
this.store = props[storeKey] || context[storeKey]
128123
this.propsMode = Boolean(props[storeKey])
@@ -134,9 +129,7 @@ export default function connectAdvanced(
134129
`or explicitly pass "${storeKey}" as a prop to "${displayName}".`
135130
)
136131

137-
this.state = {
138-
updater: this.createUpdater()
139-
}
132+
this.initSelector()
140133
this.initSubscription()
141134
}
142135

@@ -159,19 +152,25 @@ export default function connectAdvanced(
159152
// dispatching an action in its componentWillMount, we have to re-run the select and maybe
160153
// re-render.
161154
this.subscription.trySubscribe()
162-
this.runUpdater()
155+
this.selector.run(this.props)
156+
if (this.selector.shouldComponentUpdate) this.forceUpdate()
157+
}
158+
159+
componentWillReceiveProps(nextProps) {
160+
this.selector.run(nextProps)
163161
}
164162

165-
shouldComponentUpdate(_, nextState) {
166-
return nextState.shouldComponentUpdate
163+
shouldComponentUpdate() {
164+
return this.selector.shouldComponentUpdate
167165
}
168166

169167
componentWillUnmount() {
170168
if (this.subscription) this.subscription.tryUnsubscribe()
171169
this.subscription = null
172170
this.notifyNestedSubs = noop
173171
this.store = null
174-
this.isUnmounted = true
172+
this.selector.run = noop
173+
this.selector.shouldComponentUpdate = false
175174
}
176175

177176
getWrappedInstance() {
@@ -186,17 +185,10 @@ export default function connectAdvanced(
186185
this.wrappedInstance = ref
187186
}
188187

189-
createUpdater() {
188+
initSelector() {
190189
const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)
191-
return makeUpdater(sourceSelector, this.store)
192-
}
193-
194-
runUpdater(callback = noop) {
195-
if (this.isUnmounted) {
196-
return
197-
}
198-
199-
this.setState(prevState => prevState.updater(this.props, prevState), callback)
190+
this.selector = makeSelectorStateful(sourceSelector, this.store)
191+
this.selector.run(this.props)
200192
}
201193

202194
initSubscription() {
@@ -217,7 +209,24 @@ export default function connectAdvanced(
217209
}
218210

219211
onStateChange() {
220-
this.runUpdater(this.notifyNestedSubs)
212+
this.selector.run(this.props)
213+
214+
if (!this.selector.shouldComponentUpdate) {
215+
this.notifyNestedSubs()
216+
} else {
217+
this.componentDidUpdate = this.notifyNestedSubsOnComponentDidUpdate
218+
this.setState(dummyState)
219+
}
220+
}
221+
222+
notifyNestedSubsOnComponentDidUpdate() {
223+
// `componentDidUpdate` is conditionally implemented when `onStateChange` determines it
224+
// needs to notify nested subs. Once called, it unimplements itself until further state
225+
// changes occur. Doing it this way vs having a permanent `componentDidUpdate` that does
226+
// a boolean check every time avoids an extra method call most of the time, resulting
227+
// in some perf boost.
228+
this.componentDidUpdate = undefined
229+
this.notifyNestedSubs()
221230
}
222231

223232
isSubscribed() {
@@ -238,10 +247,13 @@ export default function connectAdvanced(
238247
}
239248

240249
render() {
241-
if (this.state.error) {
242-
throw this.state.error
250+
const selector = this.selector
251+
selector.shouldComponentUpdate = false
252+
253+
if (selector.error) {
254+
throw selector.error
243255
} else {
244-
return createElement(WrappedComponent, this.addExtraProps(this.state.props))
256+
return createElement(WrappedComponent, this.addExtraProps(selector.props))
245257
}
246258
}
247259
}
@@ -251,13 +263,13 @@ export default function connectAdvanced(
251263
Connect.childContextTypes = childContextTypes
252264
Connect.contextTypes = contextTypes
253265
Connect.propTypes = contextTypes
254-
Connect.getDerivedStateFromProps = getDerivedStateFromProps
255266

256267
if (process.env.NODE_ENV !== 'production') {
257-
Connect.prototype.componentDidUpdate = function componentDidUpdate() {
268+
Connect.prototype.componentWillUpdate = function componentWillUpdate() {
258269
// We are hot reloading!
259270
if (this.version !== version) {
260271
this.version = version
272+
this.initSelector()
261273

262274
// If any connected descendants don't hot reload (and resubscribe in the process), their
263275
// listeners will be lost when we unsubscribe. Unfortunately, by copying over all
@@ -275,16 +287,10 @@ export default function connectAdvanced(
275287
this.subscription.trySubscribe()
276288
oldListeners.forEach(listener => this.subscription.listeners.subscribe(listener))
277289
}
278-
279-
const updater = this.createUpdater()
280-
this.setState({updater})
281-
this.runUpdater()
282290
}
283291
}
284292
}
285293

286-
polyfill(Connect)
287-
288294
return hoistStatics(Connect, WrappedComponent)
289295
}
290296
}

0 commit comments

Comments
 (0)