Skip to content

Commit caaa0b0

Browse files
authored
Reset instance vars before calling commit phase lifecycles (#10481)
1 parent 072b1d9 commit caaa0b0

File tree

2 files changed

+45
-0
lines changed

2 files changed

+45
-0
lines changed

src/renderers/shared/fiber/ReactFiberCommitWork.js

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
6666
if (__DEV__) {
6767
var callComponentWillUnmountWithTimerInDev = function(current, instance) {
6868
startPhaseTimer(current, 'componentWillUnmount');
69+
instance.props = current.memoizedProps;
70+
instance.state = current.memoizedState;
6971
instance.componentWillUnmount();
7072
stopPhaseTimer();
7173
};
@@ -87,6 +89,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
8789
}
8890
} else {
8991
try {
92+
instance.props = current.memoizedProps;
93+
instance.state = current.memoizedState;
9094
instance.componentWillUnmount();
9195
} catch (unmountError) {
9296
captureError(current, unmountError);
@@ -495,6 +499,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
495499
if (__DEV__) {
496500
startPhaseTimer(finishedWork, 'componentDidMount');
497501
}
502+
instance.props = finishedWork.memoizedProps;
503+
instance.state = finishedWork.memoizedState;
498504
instance.componentDidMount();
499505
if (__DEV__) {
500506
stopPhaseTimer();
@@ -505,6 +511,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
505511
if (__DEV__) {
506512
startPhaseTimer(finishedWork, 'componentDidUpdate');
507513
}
514+
instance.props = finishedWork.memoizedProps;
515+
instance.state = finishedWork.memoizedState;
508516
instance.componentDidUpdate(prevProps, prevState);
509517
if (__DEV__) {
510518
stopPhaseTimer();

src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js

+37
Original file line numberDiff line numberDiff line change
@@ -1123,4 +1123,41 @@ describe('ReactIncrementalErrorHandling', () => {
11231123
);
11241124
});
11251125
});
1126+
1127+
it('resets instance variables before unmounting failed node', () => {
1128+
spyOn(console, 'error');
1129+
1130+
class ErrorBoundary extends React.Component {
1131+
state = {error: null};
1132+
componentDidCatch(error) {
1133+
this.setState({error});
1134+
}
1135+
render() {
1136+
return this.state.error ? null : this.props.children;
1137+
}
1138+
}
1139+
class Foo extends React.Component {
1140+
state = {step: 0};
1141+
componentDidMount() {
1142+
this.setState({step: 1});
1143+
}
1144+
componentWillUnmount() {
1145+
ReactNoop.yield('componentWillUnmount: ' + this.state.step);
1146+
}
1147+
render() {
1148+
ReactNoop.yield('render: ' + this.state.step);
1149+
if (this.state.step > 0) {
1150+
throw new Error('oops');
1151+
}
1152+
return null;
1153+
}
1154+
}
1155+
1156+
ReactNoop.render(<ErrorBoundary><Foo /></ErrorBoundary>);
1157+
expect(ReactNoop.flush()).toEqual([
1158+
'render: 0',
1159+
'render: 1',
1160+
'componentWillUnmount: 0',
1161+
]);
1162+
});
11261163
});

0 commit comments

Comments
 (0)