Skip to content

Commit 431dca9

Browse files
authored
Update debugRenderPhaseSideEffects behavior (facebook#12057)
Update debugRenderPhaseSideEffects behavior This feature flag no longer double-invokes componentWillMount, componentWillReceiveProps, componentWillUpdate, or shouldComponentUpdate. It continues to double-invoke the constructor, render, and setState updater functions as well as the recently added, static getDerivedStateFromProps method Tests have been updated.
1 parent d0e75dc commit 431dca9

File tree

3 files changed

+35
-31
lines changed

3 files changed

+35
-31
lines changed

packages/react-reconciler/src/ReactFiberBeginWork.js

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -220,15 +220,6 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
220220
constructClassInstance(workInProgress, workInProgress.pendingProps);
221221
mountClassInstance(workInProgress, renderExpirationTime);
222222

223-
// Simulate an async bailout/interruption by invoking lifecycle twice.
224-
// We do this here rather than inside of ReactFiberClassComponent,
225-
// To more realistically simulate the interruption behavior of async,
226-
// Which would never call componentWillMount() twice on the same instance.
227-
if (debugRenderPhaseSideEffects) {
228-
constructClassInstance(workInProgress, workInProgress.pendingProps);
229-
mountClassInstance(workInProgress, renderExpirationTime);
230-
}
231-
232223
shouldUpdate = true;
233224
} else {
234225
invariant(false, 'Resuming work not yet implemented.');

packages/react-reconciler/src/ReactFiberClassComponent.js

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,6 @@ export default function(
199199
);
200200
stopPhaseTimer();
201201

202-
// Simulate an async bailout/interruption by invoking lifecycle twice.
203-
if (debugRenderPhaseSideEffects) {
204-
instance.shouldComponentUpdate(newProps, newState, newContext);
205-
}
206-
207202
if (__DEV__) {
208203
warning(
209204
shouldUpdate !== undefined,
@@ -402,6 +397,12 @@ export default function(
402397
const context = needsContext
403398
? getMaskedContext(workInProgress, unmaskedContext)
404399
: emptyObject;
400+
401+
// Instantiate twice to help detect side-effects.
402+
if (debugRenderPhaseSideEffects) {
403+
new ctor(props, context); // eslint-disable-line no-new
404+
}
405+
405406
const instance = new ctor(props, context);
406407
const state =
407408
instance.state !== null && instance.state !== undefined
@@ -537,11 +538,6 @@ export default function(
537538
startPhaseTimer(workInProgress, 'componentWillReceiveProps');
538539
instance.UNSAFE_componentWillReceiveProps(newProps, newContext);
539540
stopPhaseTimer();
540-
541-
// Simulate an async bailout/interruption by invoking lifecycle twice.
542-
if (debugRenderPhaseSideEffects) {
543-
instance.UNSAFE_componentWillReceiveProps(newProps, newContext);
544-
}
545541
}
546542

547543
if (instance.state !== oldState) {
@@ -589,6 +585,15 @@ export default function(
589585
}
590586
}
591587

588+
if (debugRenderPhaseSideEffects) {
589+
// Invoke method an extra time to help detect side-effects.
590+
type.getDerivedStateFromProps.call(
591+
null,
592+
props,
593+
workInProgress.memoizedState,
594+
);
595+
}
596+
592597
const partialState = type.getDerivedStateFromProps.call(
593598
null,
594599
props,
@@ -916,11 +921,6 @@ export default function(
916921
startPhaseTimer(workInProgress, 'componentWillUpdate');
917922
instance.UNSAFE_componentWillUpdate(newProps, newState, newContext);
918923
stopPhaseTimer();
919-
920-
// Simulate an async bailout/interruption by invoking lifecycle twice.
921-
if (debugRenderPhaseSideEffects) {
922-
instance.UNSAFE_componentWillUpdate(newProps, newState, newContext);
923-
}
924924
}
925925
}
926926
if (typeof instance.componentDidUpdate === 'function') {

packages/react/src/__tests__/ReactAsyncClassComponent-test.internal.js

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ describe('ReactAsyncClassComponent', () => {
2828
let shouldComponentUpdate = false;
2929
class ClassComponent extends React.Component {
3030
state = {};
31+
static getDerivedStateFromProps() {
32+
log.push('getDerivedStateFromProps');
33+
return null;
34+
}
3135
constructor(props) {
3236
super(props);
3337
log.push('constructor');
@@ -60,11 +64,21 @@ describe('ReactAsyncClassComponent', () => {
6064
}
6165
}
6266

63-
const component = ReactTestRenderer.create(<ClassComponent />);
67+
let component;
68+
69+
expect(() => {
70+
component = ReactTestRenderer.create(<ClassComponent />);
71+
}).toWarnDev(
72+
'ClassComponent: Defines both componentWillReceiveProps() ' +
73+
'and static getDerivedStateFromProps() methods. ' +
74+
'We recommend using only getDerivedStateFromProps().',
75+
);
76+
6477
expect(log).toEqual([
6578
'constructor',
66-
'componentWillMount',
6779
'constructor',
80+
'getDerivedStateFromProps',
81+
'getDerivedStateFromProps',
6882
'componentWillMount',
6983
'render',
7084
'render',
@@ -77,11 +91,10 @@ describe('ReactAsyncClassComponent', () => {
7791
component.update(<ClassComponent />);
7892
expect(log).toEqual([
7993
'componentWillReceiveProps',
80-
'componentWillReceiveProps',
81-
'shouldComponentUpdate',
94+
'getDerivedStateFromProps',
95+
'getDerivedStateFromProps',
8296
'shouldComponentUpdate',
8397
'componentWillUpdate',
84-
'componentWillUpdate',
8598
'render',
8699
'render',
87100
'componentDidUpdate',
@@ -93,8 +106,8 @@ describe('ReactAsyncClassComponent', () => {
93106
component.update(<ClassComponent />);
94107
expect(log).toEqual([
95108
'componentWillReceiveProps',
96-
'componentWillReceiveProps',
97-
'shouldComponentUpdate',
109+
'getDerivedStateFromProps',
110+
'getDerivedStateFromProps',
98111
'shouldComponentUpdate',
99112
]);
100113
});

0 commit comments

Comments
 (0)