Skip to content

Commit 7fec380

Browse files
authored
Log and show error overlay for commit phase errors (#21723)
* Enable skipped tests from #21723 * Report uncaught errors in DEV * Clear caught error This is not necessary (as proven by tests) because next invokeGuardedCallback clears it anyway. But I'll keep it for consistency with other calls.
1 parent 27c9c95 commit 7fec380

File tree

3 files changed

+86
-32
lines changed

3 files changed

+86
-32
lines changed

packages/react-dom/src/__tests__/ReactDOMConsoleErrorReporting-test.js

+8-16
Original file line numberDiff line numberDiff line change
@@ -313,8 +313,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
313313
}
314314
});
315315

316-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
317-
xit('logs layout effect errors without an error boundary', () => {
316+
it('logs layout effect errors without an error boundary', () => {
318317
spyOnDevAndProd(console, 'error');
319318

320319
function Foo() {
@@ -382,8 +381,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
382381
}
383382
});
384383

385-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
386-
xit('logs layout effect errors with an error boundary', () => {
384+
it('logs layout effect errors with an error boundary', () => {
387385
spyOnDevAndProd(console, 'error');
388386

389387
function Foo() {
@@ -453,8 +451,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
453451
}
454452
});
455453

456-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
457-
xit('logs passive effect errors without an error boundary', () => {
454+
it('logs passive effect errors without an error boundary', () => {
458455
spyOnDevAndProd(console, 'error');
459456

460457
function Foo() {
@@ -522,8 +519,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
522519
}
523520
});
524521

525-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
526-
xit('logs passive effect errors with an error boundary', () => {
522+
it('logs passive effect errors with an error boundary', () => {
527523
spyOnDevAndProd(console, 'error');
528524

529525
function Foo() {
@@ -827,8 +823,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
827823
}
828824
});
829825

830-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
831-
xit('logs layout effect errors without an error boundary', () => {
826+
it('logs layout effect errors without an error boundary', () => {
832827
spyOnDevAndProd(console, 'error');
833828

834829
function Foo() {
@@ -898,8 +893,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
898893
}
899894
});
900895

901-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
902-
xit('logs layout effect errors with an error boundary', () => {
896+
it('logs layout effect errors with an error boundary', () => {
903897
spyOnDevAndProd(console, 'error');
904898

905899
function Foo() {
@@ -972,8 +966,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
972966
}
973967
});
974968

975-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
976-
xit('logs passive effect errors without an error boundary', () => {
969+
it('logs passive effect errors without an error boundary', () => {
977970
spyOnDevAndProd(console, 'error');
978971

979972
function Foo() {
@@ -1043,8 +1036,7 @@ describe('ReactDOMConsoleErrorReporting', () => {
10431036
}
10441037
});
10451038

1046-
// TODO: this is broken due to https://github.com/facebook/react/issues/21712.
1047-
xit('logs passive effect errors with an error boundary', () => {
1039+
it('logs passive effect errors with an error boundary', () => {
10481040
spyOnDevAndProd(console, 'error');
10491041

10501042
function Foo() {

packages/react-reconciler/src/ReactFiberCommitWork.new.js

+39-8
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ import {
140140
} from './ReactHookEffectTags';
141141
import {didWarnAboutReassigningProps} from './ReactFiberBeginWork.new';
142142
import {doesFiberContain} from './ReactFiberTreeReflection';
143+
import {invokeGuardedCallback, clearCaughtError} from 'shared/ReactErrorUtils';
143144

144145
let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
145146
if (__DEV__) {
@@ -160,6 +161,20 @@ let nextEffect: Fiber | null = null;
160161
let inProgressLanes: Lanes | null = null;
161162
let inProgressRoot: FiberRoot | null = null;
162163

164+
function reportUncaughtErrorInDEV(error) {
165+
// Wrapping each small part of the commit phase into a guarded
166+
// callback is a bit too slow (https://github.com/facebook/react/pull/21666).
167+
// But we rely on it to surface errors to DEV tools like overlays
168+
// (https://github.com/facebook/react/issues/21712).
169+
// As a compromise, rethrow only caught errors in a guard.
170+
if (__DEV__) {
171+
invokeGuardedCallback(null, () => {
172+
throw error;
173+
});
174+
clearCaughtError();
175+
}
176+
}
177+
163178
const callComponentWillUnmountWithTimer = function(current, instance) {
164179
instance.props = current.memoizedProps;
165180
instance.state = current.memoizedState;
@@ -186,8 +201,9 @@ function safelyCallCommitHookLayoutEffectListMount(
186201
) {
187202
try {
188203
commitHookEffectListMount(HookLayout, current);
189-
} catch (unmountError) {
190-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
204+
} catch (error) {
205+
reportUncaughtErrorInDEV(error);
206+
captureCommitPhaseError(current, nearestMountedAncestor, error);
191207
}
192208
}
193209

@@ -199,8 +215,9 @@ function safelyCallComponentWillUnmount(
199215
) {
200216
try {
201217
callComponentWillUnmountWithTimer(current, instance);
202-
} catch (unmountError) {
203-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
218+
} catch (error) {
219+
reportUncaughtErrorInDEV(error);
220+
captureCommitPhaseError(current, nearestMountedAncestor, error);
204221
}
205222
}
206223

@@ -212,17 +229,19 @@ function safelyCallComponentDidMount(
212229
) {
213230
try {
214231
instance.componentDidMount();
215-
} catch (unmountError) {
216-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
232+
} catch (error) {
233+
reportUncaughtErrorInDEV(error);
234+
captureCommitPhaseError(current, nearestMountedAncestor, error);
217235
}
218236
}
219237

220238
// Capture errors so they don't interrupt mounting.
221239
function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
222240
try {
223241
commitAttachRef(current);
224-
} catch (unmountError) {
225-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
242+
} catch (error) {
243+
reportUncaughtErrorInDEV(error);
244+
captureCommitPhaseError(current, nearestMountedAncestor, error);
226245
}
227246
}
228247

@@ -246,6 +265,7 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
246265
ref(null);
247266
}
248267
} catch (error) {
268+
reportUncaughtErrorInDEV(error);
249269
captureCommitPhaseError(current, nearestMountedAncestor, error);
250270
}
251271
} else {
@@ -262,6 +282,7 @@ function safelyCallDestroy(
262282
try {
263283
destroy();
264284
} catch (error) {
285+
reportUncaughtErrorInDEV(error);
265286
captureCommitPhaseError(current, nearestMountedAncestor, error);
266287
}
267288
}
@@ -323,6 +344,7 @@ function commitBeforeMutationEffects_complete() {
323344
try {
324345
commitBeforeMutationEffectsOnFiber(fiber);
325346
} catch (error) {
347+
reportUncaughtErrorInDEV(error);
326348
captureCommitPhaseError(fiber, fiber.return, error);
327349
}
328350
resetCurrentDebugFiberInDEV();
@@ -2065,6 +2087,7 @@ function commitMutationEffects_begin(root: FiberRoot) {
20652087
try {
20662088
commitDeletion(root, childToDelete, fiber);
20672089
} catch (error) {
2090+
reportUncaughtErrorInDEV(error);
20682091
captureCommitPhaseError(childToDelete, fiber, error);
20692092
}
20702093
}
@@ -2087,6 +2110,7 @@ function commitMutationEffects_complete(root: FiberRoot) {
20872110
try {
20882111
commitMutationEffectsOnFiber(fiber, root);
20892112
} catch (error) {
2113+
reportUncaughtErrorInDEV(error);
20902114
captureCommitPhaseError(fiber, fiber.return, error);
20912115
}
20922116
resetCurrentDebugFiberInDEV();
@@ -2329,6 +2353,7 @@ function commitLayoutMountEffects_complete(
23292353
try {
23302354
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
23312355
} catch (error) {
2356+
reportUncaughtErrorInDEV(error);
23322357
captureCommitPhaseError(fiber, fiber.return, error);
23332358
}
23342359
resetCurrentDebugFiberInDEV();
@@ -2382,6 +2407,7 @@ function commitPassiveMountEffects_complete(
23822407
try {
23832408
commitPassiveMountOnFiber(root, fiber);
23842409
} catch (error) {
2410+
reportUncaughtErrorInDEV(error);
23852411
captureCommitPhaseError(fiber, fiber.return, error);
23862412
}
23872413
resetCurrentDebugFiberInDEV();
@@ -2664,6 +2690,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
26642690
try {
26652691
commitHookEffectListMount(HookLayout | HookHasEffect, fiber);
26662692
} catch (error) {
2693+
reportUncaughtErrorInDEV(error);
26672694
captureCommitPhaseError(fiber, fiber.return, error);
26682695
}
26692696
break;
@@ -2673,6 +2700,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
26732700
try {
26742701
instance.componentDidMount();
26752702
} catch (error) {
2703+
reportUncaughtErrorInDEV(error);
26762704
captureCommitPhaseError(fiber, fiber.return, error);
26772705
}
26782706
break;
@@ -2692,6 +2720,7 @@ function invokePassiveEffectMountInDEV(fiber: Fiber): void {
26922720
try {
26932721
commitHookEffectListMount(HookPassive | HookHasEffect, fiber);
26942722
} catch (error) {
2723+
reportUncaughtErrorInDEV(error);
26952724
captureCommitPhaseError(fiber, fiber.return, error);
26962725
}
26972726
break;
@@ -2715,6 +2744,7 @@ function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {
27152744
fiber.return,
27162745
);
27172746
} catch (error) {
2747+
reportUncaughtErrorInDEV(error);
27182748
captureCommitPhaseError(fiber, fiber.return, error);
27192749
}
27202750
break;
@@ -2745,6 +2775,7 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {
27452775
fiber.return,
27462776
);
27472777
} catch (error) {
2778+
reportUncaughtErrorInDEV(error);
27482779
captureCommitPhaseError(fiber, fiber.return, error);
27492780
}
27502781
}

0 commit comments

Comments
 (0)