Skip to content

Commit 9578017

Browse files
committed
Revert "Merge branch 'pre-6.x' into master"
This reverts commit eb960c4, reversing changes made to b255a46.
1 parent eb960c4 commit 9578017

File tree

5 files changed

+70
-128
lines changed

5 files changed

+70
-128
lines changed

package-lock.json

Lines changed: 10 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
"hoist-non-react-statics": "^2.5.5",
4747
"invariant": "^2.2.4",
4848
"loose-envify": "^1.1.0",
49-
"prop-types": "^15.6.1"
49+
"prop-types": "^15.6.1",
50+
"react-lifecycles-compat": "^3.0.0"
5051
},
5152
"devDependencies": {
5253
"babel-cli": "^6.26.0",
@@ -88,6 +89,8 @@
8889
"jest": "^23.4.1",
8990
"jest-dom": "^1.12.0",
9091
"npm-run": "^5.0.1",
92+
"react": "^16.3.2",
93+
"react-dom": "^16.3.2",
9194
"react-testing-library": "^5.0.0",
9295
"redux": "^4.0.0",
9396
"rimraf": "^2.6.2",

src/components/connectAdvanced.js

Lines changed: 48 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,35 @@
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'
45

56
import Subscription from '../utils/Subscription'
67
import { storeShape, subscriptionShape } from '../utils/PropTypes'
78

89
let hotReloadingVersion = 0
910
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,
20+
}
21+
}
22+
return {
23+
shouldComponentUpdate: false,
24+
}
25+
} catch (error) {
26+
return {
27+
shouldComponentUpdate: true,
28+
error,
29+
}
30+
}
31+
}
32+
}
1033

1134
export default function connectAdvanced(
1235
/*
@@ -65,6 +88,10 @@ export default function connectAdvanced(
6588
[subscriptionKey]: subscriptionShape,
6689
}
6790

91+
function getDerivedStateFromProps(nextProps, prevState) {
92+
return prevState.updater(nextProps, prevState)
93+
}
94+
6895
return function wrapWithConnect(WrappedComponent) {
6996
invariant(
7097
typeof WrappedComponent == 'function',
@@ -107,14 +134,10 @@ export default function connectAdvanced(
107134
`or explicitly pass "${storeKey}" as a prop to "${displayName}".`
108135
)
109136

110-
this.createSelector()
111137
this.state = {
112-
updateCount: 0
138+
updater: this.createUpdater()
113139
}
114-
this.storeState = this.store.getState()
115140
this.initSubscription()
116-
this.derivedProps = this.derivedPropsUpdater()
117-
this.received = this.props
118141
}
119142

120143
getChildContext() {
@@ -136,17 +159,11 @@ export default function connectAdvanced(
136159
// dispatching an action in its componentWillMount, we have to re-run the select and maybe
137160
// re-render.
138161
this.subscription.trySubscribe()
139-
this.triggerUpdateOnStoreStateChange()
162+
this.runUpdater()
140163
}
141164

142-
shouldComponentUpdate(nextProps) {
143-
this.received = nextProps
144-
// received a prop update, store state updates are handled in onStateChange
145-
const oldProps = this.derivedProps
146-
const newProps = this.updateDerivedProps(nextProps)
147-
if (this.error) return true
148-
const sCU = newProps !== oldProps
149-
return sCU
165+
shouldComponentUpdate(_, nextState) {
166+
return nextState.shouldComponentUpdate
150167
}
151168

152169
componentWillUnmount() {
@@ -157,31 +174,6 @@ export default function connectAdvanced(
157174
this.isUnmounted = true
158175
}
159176

160-
updateDerivedProps(nextProps) {
161-
this.derivedProps = this.derivedPropsUpdater(nextProps)
162-
return this.derivedProps
163-
}
164-
165-
derivedPropsUpdater(props = this.props) {
166-
// runs when props change, or the store state changes
167-
// and generates the derived props for connected components
168-
try {
169-
const nextProps = this.sourceSelector(this.storeState, props)
170-
if (nextProps !== this.derivedProps || this.error) {
171-
this.error = null
172-
return nextProps
173-
}
174-
return this.derivedProps
175-
} catch (error) {
176-
this.error = error
177-
return this.derivedProps
178-
}
179-
}
180-
181-
createSelector() {
182-
this.sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)
183-
}
184-
185177
getWrappedInstance() {
186178
invariant(withRef,
187179
`To access the wrapped instance, you need to specify ` +
@@ -194,24 +186,17 @@ export default function connectAdvanced(
194186
this.wrappedInstance = ref
195187
}
196188

197-
triggerUpdateOnStoreStateChange(callback = noop) {
198-
// runs when an action is dispatched by the store we are listening to
199-
// if the store state has changed, we save that and update the component state
200-
// to force a re-generation of derived props
189+
createUpdater() {
190+
const sourceSelector = selectorFactory(this.store.dispatch, selectorFactoryOptions)
191+
return makeUpdater(sourceSelector, this.store)
192+
}
193+
194+
runUpdater(callback = noop) {
201195
if (this.isUnmounted) {
202196
return
203197
}
204198

205-
this.setState(prevState => {
206-
const newState = this.store.getState()
207-
if (this.storeState === newState) {
208-
return prevState
209-
}
210-
this.storeState = newState
211-
return {
212-
updateCount: prevState.updateCount++
213-
}
214-
}, callback)
199+
this.setState(prevState => prevState.updater(this.props, prevState), callback)
215200
}
216201

217202
initSubscription() {
@@ -232,7 +217,7 @@ export default function connectAdvanced(
232217
}
233218

234219
onStateChange() {
235-
this.triggerUpdateOnStoreStateChange(this.notifyNestedSubs)
220+
this.runUpdater(this.notifyNestedSubs)
236221
}
237222

238223
isSubscribed() {
@@ -253,16 +238,10 @@ export default function connectAdvanced(
253238
}
254239

255240
render() {
256-
if (this.received !== this.props) {
257-
// forceUpdate() was called on this component, which skips sCU
258-
// so manually update derived props
259-
this.received = this.props
260-
this.updateDerivedProps(this.props)
261-
}
262-
if (this.error) {
263-
throw this.error
241+
if (this.state.error) {
242+
throw this.state.error
264243
} else {
265-
return createElement(WrappedComponent, this.addExtraProps(this.derivedProps))
244+
return createElement(WrappedComponent, this.addExtraProps(this.state.props))
266245
}
267246
}
268247
}
@@ -272,6 +251,7 @@ export default function connectAdvanced(
272251
Connect.childContextTypes = childContextTypes
273252
Connect.contextTypes = contextTypes
274253
Connect.propTypes = contextTypes
254+
Connect.getDerivedStateFromProps = getDerivedStateFromProps
275255

276256
if (process.env.NODE_ENV !== 'production') {
277257
Connect.prototype.componentDidUpdate = function componentDidUpdate() {
@@ -296,12 +276,15 @@ export default function connectAdvanced(
296276
oldListeners.forEach(listener => this.subscription.listeners.subscribe(listener))
297277
}
298278

299-
this.createSelector()
300-
this.triggerUpdateOnStoreStateChange()
279+
const updater = this.createUpdater()
280+
this.setState({updater})
281+
this.runUpdater()
301282
}
302283
}
303284
}
304285

286+
polyfill(Connect)
287+
305288
return hoistStatics(Connect, WrappedComponent)
306289
}
307290
}

test/components/Provider.spec.js

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -214,12 +214,10 @@ describe('React', () => {
214214
}
215215
}
216216

217-
const childCalls = []
218217
@connect((state, parentProps) => {
219218
childMapStateInvokes++
220-
childCalls.push([state, parentProps.parentState])
221219
// The state from parent props should always be consistent with the current state
222-
//expect(state).toEqual(parentProps.parentState)
220+
expect(state).toEqual(parentProps.parentState)
223221
return {}
224222
})
225223
class ChildContainer extends Component {
@@ -238,31 +236,16 @@ describe('React', () => {
238236

239237
// The store state stays consistent when setState calls are batched
240238
store.dispatch({ type: 'APPEND', body: 'c' })
241-
expect(childMapStateInvokes).toBe(3)
242-
expect(childCalls).toEqual([
243-
['a', 'a'],
244-
['a', 'ac'], // parent updates first, passes props
245-
['ac', 'ac'] // then store update is processed
246-
])
239+
expect(childMapStateInvokes).toBe(2)
247240

248241
// setState calls DOM handlers are batched
249-
250242
const button = tester.getByText('change')
251243
rtl.fireEvent.click(button)
252244
expect(childMapStateInvokes).toBe(3)
253245

254246
// Provider uses unstable_batchedUpdates() under the hood
255247
store.dispatch({ type: 'APPEND', body: 'd' })
256-
expect(childCalls).toEqual([
257-
['a', 'a'],
258-
['a', 'ac'], // parent updates first, passes props
259-
['ac', 'ac'], // then store update is processed
260-
['ac', 'acb'], // parent updates first, passes props
261-
['acb', 'acb'], // then store update is processed
262-
['acb', 'acbd'], // parent updates first, passes props
263-
['acbd', 'acbd'], // then store update is processed
264-
])
265-
expect(childMapStateInvokes).toBe(7)
248+
expect(childMapStateInvokes).toBe(4)
266249
})
267250

268251
it('works in <StrictMode> without warnings (React 16.3+)', () => {

test/components/connect.spec.js

Lines changed: 5 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1773,12 +1773,10 @@ describe('React', () => {
17731773
}
17741774
}
17751775

1776-
const childCalls = []
17771776
@connect((state, parentProps) => {
17781777
childMapStateInvokes++
1779-
childCalls.push([state, parentProps.parentState])
17801778
// The state from parent props should always be consistent with the current state
1781-
//expect(state).toEqual(parentProps.parentState)
1779+
expect(state).toEqual(parentProps.parentState)
17821780
return {}
17831781
})
17841782
class ChildContainer extends Component {
@@ -1794,37 +1792,20 @@ describe('React', () => {
17941792
)
17951793

17961794
expect(childMapStateInvokes).toBe(1)
1797-
expect(childCalls).toEqual([
1798-
['a', 'a']
1799-
])
18001795

18011796
// The store state stays consistent when setState calls are batched
18021797
ReactDOM.unstable_batchedUpdates(() => {
18031798
store.dispatch({ type: 'APPEND', body: 'c' })
18041799
})
1805-
expect(childMapStateInvokes).toBe(3)
1806-
expect(childCalls).toEqual([
1807-
['a', 'a'],
1808-
['a', 'ac'],
1809-
['ac', 'ac'],
1810-
])
1800+
expect(childMapStateInvokes).toBe(2)
18111801

18121802
// setState calls DOM handlers are batched
18131803
const button = tester.getByText('change')
18141804
rtl.fireEvent.click(button)
18151805
expect(childMapStateInvokes).toBe(3)
18161806

18171807
store.dispatch({ type: 'APPEND', body: 'd' })
1818-
expect(childMapStateInvokes).toBe(7)
1819-
expect(childCalls).toEqual([
1820-
['a', 'a'],
1821-
['a', 'ac'],
1822-
['ac', 'ac'],
1823-
['ac', 'acb'],
1824-
['acb', 'acb'],
1825-
['acb', 'acbd'],
1826-
['acbd', 'acbd'],
1827-
])
1808+
expect(childMapStateInvokes).toBe(4)
18281809
})
18291810

18301811
it('should not render the wrapped component when mapState does not produce change', () => {
@@ -2040,7 +2021,7 @@ describe('React', () => {
20402021
return { ...stateProps, ...dispatchProps, name: parentProps.name }
20412022
}
20422023

2043-
@connect(() => ({}), mapDispatchFactory, mergeParentDispatch)
2024+
@connect(null, mapDispatchFactory, mergeParentDispatch)
20442025
class Passthrough extends Component {
20452026
componentDidUpdate() {
20462027
updatedCount++
@@ -2300,9 +2281,8 @@ describe('React', () => {
23002281
@connect() // no mapStateToProps. therefore it should be transparent for subscriptions
23012282
class B extends React.Component { render() { return <C {...this.props} /> }}
23022283

2303-
let calls = []
23042284
@connect((state, props) => {
2305-
calls.push([state, props.count])
2285+
expect(props.count).toBe(state)
23062286
return { count: state * 10 + props.count }
23072287
})
23082288
class C extends React.Component { render() { return <div>{this.props.count}</div> }}
@@ -2311,12 +2291,6 @@ describe('React', () => {
23112291
rtl.render(<ProviderMock store={store}><A /></ProviderMock>)
23122292

23132293
store.dispatch({ type: 'INC' })
2314-
2315-
expect(calls).toEqual([
2316-
[0, 0],
2317-
[0, 1], // props updates first
2318-
[1, 1], // then state
2319-
])
23202294
})
23212295

23222296
it('should subscribe properly when a new store is provided via props', () => {

0 commit comments

Comments
 (0)