Reset instance vars before calling commit phase lifecycles (#10481)
Andrew Clark committed
Aug 17, 2017 at 13:52 UTC
caaa0b047db482bb84e8064fc1e269c8b752a784
2 files changed
+45
src/renderers/shared/fiber/ReactFiberCommitWork.js
+8
@@ -66,6 +66,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
66
if (__DEV__) {
67
var callComponentWillUnmountWithTimerInDev = function(current, instance) {
68
startPhaseTimer(current, 'componentWillUnmount');
69
+ instance.props = current.memoizedProps;
70
+ instance.state = current.memoizedState;
71
instance.componentWillUnmount();
72
stopPhaseTimer();
73
};
@@ -87,6 +89,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
89
}
90
} else {
91
try {
92
+ instance.props = current.memoizedProps;
93
+ instance.state = current.memoizedState;
94
instance.componentWillUnmount();
95
} catch (unmountError) {
96
captureError(current, unmountError);
@@ -495,6 +499,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
499
if (__DEV__) {
500
startPhaseTimer(finishedWork, 'componentDidMount');
501
}
502
+ instance.props = finishedWork.memoizedProps;
503
+ instance.state = finishedWork.memoizedState;
504
instance.componentDidMount();
505
if (__DEV__) {
506
stopPhaseTimer();
@@ -505,6 +511,8 @@ module.exports = function<T, P, I, TI, PI, C, CX, PL>(
511
if (__DEV__) {
512
startPhaseTimer(finishedWork, 'componentDidUpdate');
513
}
514
+ instance.props = finishedWork.memoizedProps;
515
+ instance.state = finishedWork.memoizedState;
516
instance.componentDidUpdate(prevProps, prevState);
517
if (__DEV__) {
518
stopPhaseTimer();
src/renderers/shared/fiber/__tests__/ReactIncrementalErrorHandling-test.js
+37
@@ -1123,4 +1123,41 @@ describe('ReactIncrementalErrorHandling', () => {
1123
);
1124
});
1125
});
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
+ });
1163
});