Skip to content

Commit 3add2a8

Browse files
committed
Report uncaught errors in DEV
1 parent 6b33d24 commit 3add2a8

File tree

2 files changed

+76
-16
lines changed

2 files changed

+76
-16
lines changed

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

+38-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} from 'shared/ReactErrorUtils';
143144

144145
let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
145146
if (__DEV__) {
@@ -160,6 +161,19 @@ 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+
}
175+
}
176+
163177
const callComponentWillUnmountWithTimer = function(current, instance) {
164178
instance.props = current.memoizedProps;
165179
instance.state = current.memoizedState;
@@ -186,8 +200,9 @@ function safelyCallCommitHookLayoutEffectListMount(
186200
) {
187201
try {
188202
commitHookEffectListMount(HookLayout, current);
189-
} catch (unmountError) {
190-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
203+
} catch (error) {
204+
reportUncaughtErrorInDEV(error);
205+
captureCommitPhaseError(current, nearestMountedAncestor, error);
191206
}
192207
}
193208

@@ -199,8 +214,9 @@ function safelyCallComponentWillUnmount(
199214
) {
200215
try {
201216
callComponentWillUnmountWithTimer(current, instance);
202-
} catch (unmountError) {
203-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
217+
} catch (error) {
218+
reportUncaughtErrorInDEV(error);
219+
captureCommitPhaseError(current, nearestMountedAncestor, error);
204220
}
205221
}
206222

@@ -212,17 +228,19 @@ function safelyCallComponentDidMount(
212228
) {
213229
try {
214230
instance.componentDidMount();
215-
} catch (unmountError) {
216-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
231+
} catch (error) {
232+
reportUncaughtErrorInDEV(error);
233+
captureCommitPhaseError(current, nearestMountedAncestor, error);
217234
}
218235
}
219236

220237
// Capture errors so they don't interrupt mounting.
221238
function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
222239
try {
223240
commitAttachRef(current);
224-
} catch (unmountError) {
225-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
241+
} catch (error) {
242+
reportUncaughtErrorInDEV(error);
243+
captureCommitPhaseError(current, nearestMountedAncestor, error);
226244
}
227245
}
228246

@@ -246,6 +264,7 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
246264
ref(null);
247265
}
248266
} catch (error) {
267+
reportUncaughtErrorInDEV(error);
249268
captureCommitPhaseError(current, nearestMountedAncestor, error);
250269
}
251270
} else {
@@ -262,6 +281,7 @@ function safelyCallDestroy(
262281
try {
263282
destroy();
264283
} catch (error) {
284+
reportUncaughtErrorInDEV(error);
265285
captureCommitPhaseError(current, nearestMountedAncestor, error);
266286
}
267287
}
@@ -323,6 +343,7 @@ function commitBeforeMutationEffects_complete() {
323343
try {
324344
commitBeforeMutationEffectsOnFiber(fiber);
325345
} catch (error) {
346+
reportUncaughtErrorInDEV(error);
326347
captureCommitPhaseError(fiber, fiber.return, error);
327348
}
328349
resetCurrentDebugFiberInDEV();
@@ -2065,6 +2086,7 @@ function commitMutationEffects_begin(root: FiberRoot) {
20652086
try {
20662087
commitDeletion(root, childToDelete, fiber);
20672088
} catch (error) {
2089+
reportUncaughtErrorInDEV(error);
20682090
captureCommitPhaseError(childToDelete, fiber, error);
20692091
}
20702092
}
@@ -2087,6 +2109,7 @@ function commitMutationEffects_complete(root: FiberRoot) {
20872109
try {
20882110
commitMutationEffectsOnFiber(fiber, root);
20892111
} catch (error) {
2112+
reportUncaughtErrorInDEV(error);
20902113
captureCommitPhaseError(fiber, fiber.return, error);
20912114
}
20922115
resetCurrentDebugFiberInDEV();
@@ -2329,6 +2352,7 @@ function commitLayoutMountEffects_complete(
23292352
try {
23302353
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
23312354
} catch (error) {
2355+
reportUncaughtErrorInDEV(error);
23322356
captureCommitPhaseError(fiber, fiber.return, error);
23332357
}
23342358
resetCurrentDebugFiberInDEV();
@@ -2382,6 +2406,7 @@ function commitPassiveMountEffects_complete(
23822406
try {
23832407
commitPassiveMountOnFiber(root, fiber);
23842408
} catch (error) {
2409+
reportUncaughtErrorInDEV(error);
23852410
captureCommitPhaseError(fiber, fiber.return, error);
23862411
}
23872412
resetCurrentDebugFiberInDEV();
@@ -2664,6 +2689,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
26642689
try {
26652690
commitHookEffectListMount(HookLayout | HookHasEffect, fiber);
26662691
} catch (error) {
2692+
reportUncaughtErrorInDEV(error);
26672693
captureCommitPhaseError(fiber, fiber.return, error);
26682694
}
26692695
break;
@@ -2673,6 +2699,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
26732699
try {
26742700
instance.componentDidMount();
26752701
} catch (error) {
2702+
reportUncaughtErrorInDEV(error);
26762703
captureCommitPhaseError(fiber, fiber.return, error);
26772704
}
26782705
break;
@@ -2692,6 +2719,7 @@ function invokePassiveEffectMountInDEV(fiber: Fiber): void {
26922719
try {
26932720
commitHookEffectListMount(HookPassive | HookHasEffect, fiber);
26942721
} catch (error) {
2722+
reportUncaughtErrorInDEV(error);
26952723
captureCommitPhaseError(fiber, fiber.return, error);
26962724
}
26972725
break;
@@ -2715,6 +2743,7 @@ function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {
27152743
fiber.return,
27162744
);
27172745
} catch (error) {
2746+
reportUncaughtErrorInDEV(error);
27182747
captureCommitPhaseError(fiber, fiber.return, error);
27192748
}
27202749
break;
@@ -2745,6 +2774,7 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {
27452774
fiber.return,
27462775
);
27472776
} catch (error) {
2777+
reportUncaughtErrorInDEV(error);
27482778
captureCommitPhaseError(fiber, fiber.return, error);
27492779
}
27502780
}

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

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

144145
let didWarnAboutUndefinedSnapshotBeforeUpdate: Set<mixed> | null = null;
145146
if (__DEV__) {
@@ -160,6 +161,19 @@ 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+
}
175+
}
176+
163177
const callComponentWillUnmountWithTimer = function(current, instance) {
164178
instance.props = current.memoizedProps;
165179
instance.state = current.memoizedState;
@@ -186,8 +200,9 @@ function safelyCallCommitHookLayoutEffectListMount(
186200
) {
187201
try {
188202
commitHookEffectListMount(HookLayout, current);
189-
} catch (unmountError) {
190-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
203+
} catch (error) {
204+
reportUncaughtErrorInDEV(error);
205+
captureCommitPhaseError(current, nearestMountedAncestor, error);
191206
}
192207
}
193208

@@ -199,8 +214,9 @@ function safelyCallComponentWillUnmount(
199214
) {
200215
try {
201216
callComponentWillUnmountWithTimer(current, instance);
202-
} catch (unmountError) {
203-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
217+
} catch (error) {
218+
reportUncaughtErrorInDEV(error);
219+
captureCommitPhaseError(current, nearestMountedAncestor, error);
204220
}
205221
}
206222

@@ -212,17 +228,19 @@ function safelyCallComponentDidMount(
212228
) {
213229
try {
214230
instance.componentDidMount();
215-
} catch (unmountError) {
216-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
231+
} catch (error) {
232+
reportUncaughtErrorInDEV(error);
233+
captureCommitPhaseError(current, nearestMountedAncestor, error);
217234
}
218235
}
219236

220237
// Capture errors so they don't interrupt mounting.
221238
function safelyAttachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
222239
try {
223240
commitAttachRef(current);
224-
} catch (unmountError) {
225-
captureCommitPhaseError(current, nearestMountedAncestor, unmountError);
241+
} catch (error) {
242+
reportUncaughtErrorInDEV(error);
243+
captureCommitPhaseError(current, nearestMountedAncestor, error);
226244
}
227245
}
228246

@@ -246,6 +264,7 @@ function safelyDetachRef(current: Fiber, nearestMountedAncestor: Fiber | null) {
246264
ref(null);
247265
}
248266
} catch (error) {
267+
reportUncaughtErrorInDEV(error);
249268
captureCommitPhaseError(current, nearestMountedAncestor, error);
250269
}
251270
} else {
@@ -262,6 +281,7 @@ function safelyCallDestroy(
262281
try {
263282
destroy();
264283
} catch (error) {
284+
reportUncaughtErrorInDEV(error);
265285
captureCommitPhaseError(current, nearestMountedAncestor, error);
266286
}
267287
}
@@ -323,6 +343,7 @@ function commitBeforeMutationEffects_complete() {
323343
try {
324344
commitBeforeMutationEffectsOnFiber(fiber);
325345
} catch (error) {
346+
reportUncaughtErrorInDEV(error);
326347
captureCommitPhaseError(fiber, fiber.return, error);
327348
}
328349
resetCurrentDebugFiberInDEV();
@@ -2065,6 +2086,7 @@ function commitMutationEffects_begin(root: FiberRoot) {
20652086
try {
20662087
commitDeletion(root, childToDelete, fiber);
20672088
} catch (error) {
2089+
reportUncaughtErrorInDEV(error);
20682090
captureCommitPhaseError(childToDelete, fiber, error);
20692091
}
20702092
}
@@ -2087,6 +2109,7 @@ function commitMutationEffects_complete(root: FiberRoot) {
20872109
try {
20882110
commitMutationEffectsOnFiber(fiber, root);
20892111
} catch (error) {
2112+
reportUncaughtErrorInDEV(error);
20902113
captureCommitPhaseError(fiber, fiber.return, error);
20912114
}
20922115
resetCurrentDebugFiberInDEV();
@@ -2329,6 +2352,7 @@ function commitLayoutMountEffects_complete(
23292352
try {
23302353
commitLayoutEffectOnFiber(root, current, fiber, committedLanes);
23312354
} catch (error) {
2355+
reportUncaughtErrorInDEV(error);
23322356
captureCommitPhaseError(fiber, fiber.return, error);
23332357
}
23342358
resetCurrentDebugFiberInDEV();
@@ -2382,6 +2406,7 @@ function commitPassiveMountEffects_complete(
23822406
try {
23832407
commitPassiveMountOnFiber(root, fiber);
23842408
} catch (error) {
2409+
reportUncaughtErrorInDEV(error);
23852410
captureCommitPhaseError(fiber, fiber.return, error);
23862411
}
23872412
resetCurrentDebugFiberInDEV();
@@ -2664,6 +2689,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
26642689
try {
26652690
commitHookEffectListMount(HookLayout | HookHasEffect, fiber);
26662691
} catch (error) {
2692+
reportUncaughtErrorInDEV(error);
26672693
captureCommitPhaseError(fiber, fiber.return, error);
26682694
}
26692695
break;
@@ -2673,6 +2699,7 @@ function invokeLayoutEffectMountInDEV(fiber: Fiber): void {
26732699
try {
26742700
instance.componentDidMount();
26752701
} catch (error) {
2702+
reportUncaughtErrorInDEV(error);
26762703
captureCommitPhaseError(fiber, fiber.return, error);
26772704
}
26782705
break;
@@ -2692,6 +2719,7 @@ function invokePassiveEffectMountInDEV(fiber: Fiber): void {
26922719
try {
26932720
commitHookEffectListMount(HookPassive | HookHasEffect, fiber);
26942721
} catch (error) {
2722+
reportUncaughtErrorInDEV(error);
26952723
captureCommitPhaseError(fiber, fiber.return, error);
26962724
}
26972725
break;
@@ -2715,6 +2743,7 @@ function invokeLayoutEffectUnmountInDEV(fiber: Fiber): void {
27152743
fiber.return,
27162744
);
27172745
} catch (error) {
2746+
reportUncaughtErrorInDEV(error);
27182747
captureCommitPhaseError(fiber, fiber.return, error);
27192748
}
27202749
break;
@@ -2745,6 +2774,7 @@ function invokePassiveEffectUnmountInDEV(fiber: Fiber): void {
27452774
fiber.return,
27462775
);
27472776
} catch (error) {
2777+
reportUncaughtErrorInDEV(error);
27482778
captureCommitPhaseError(fiber, fiber.return, error);
27492779
}
27502780
}

0 commit comments

Comments
 (0)