Skip to content

Commit dad75d3

Browse files
committed
[ReactDebugTools] wrap uncaught error from rendering user's component
1 parent 60cb32b commit dad75d3

File tree

2 files changed

+37
-1
lines changed

2 files changed

+37
-1
lines changed

packages/react-debug-tools/src/ReactDebugCustomErrors.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
export const ErrorsNames = {
1818
UNSUPPORTTED_FEATURE_ERROR: 'UnsupportedFeatureError',
19+
RENDER_FUNCTION_ERROR: 'RenderFunctionError',
1920
};
2021

2122
// For now we just override the name. If we decide to move react-debug-tools to
@@ -25,3 +26,13 @@ export function createUnsupportedFeatureError(message: string = '') {
2526
error.name = ErrorsNames.UNSUPPORTTED_FEATURE_ERROR;
2627
return error;
2728
}
29+
30+
export function createRenderFunctionError(
31+
message: string = '',
32+
options: Object = {},
33+
) {
34+
// $FlowFixMe: Flow doesn't know about 2nd argument of Error constructor
35+
const error = new Error(message, options);
36+
error.name = ErrorsNames.RENDER_FUNCTION_ERROR;
37+
return error;
38+
}

packages/react-debug-tools/src/ReactDebugHooks.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ import {
2929
ContextProvider,
3030
ForwardRef,
3131
} from 'react-reconciler/src/ReactWorkTags';
32-
import {createUnsupportedFeatureError} from './ReactDebugCustomErrors';
32+
import {
33+
createUnsupportedFeatureError,
34+
createRenderFunctionError,
35+
ErrorsNames,
36+
} from './ReactDebugCustomErrors';
3337

3438
type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;
3539

@@ -666,6 +670,23 @@ function processDebugValues(
666670
}
667671
}
668672

673+
function handleRenderFunctionError(error: any): void {
674+
// original error might be any type.
675+
const isError = error instanceof Error;
676+
if (isError && error.name === ErrorsNames.UNSUPPORTTED_FEATURE_ERROR) {
677+
throw error;
678+
}
679+
// If the error is not caused by an unsupported feature, it means
680+
// that the error is caused by user's code in renderFunction.
681+
// In this case, we should wrap the original error inside a custom error
682+
// so that devtools can show a clear message for it.
683+
const messgae: string =
684+
isError && error.message
685+
? error.message
686+
: 'Error rendering inspected component';
687+
throw createRenderFunctionError(messgae, {cause: error});
688+
}
689+
669690
export function inspectHooks<Props>(
670691
renderFunction: Props => React$Node,
671692
props: Props,
@@ -685,6 +706,8 @@ export function inspectHooks<Props>(
685706
try {
686707
ancestorStackError = new Error();
687708
renderFunction(props);
709+
} catch (error) {
710+
handleRenderFunctionError(error);
688711
} finally {
689712
readHookLog = hookLog;
690713
hookLog = [];
@@ -729,6 +752,8 @@ function inspectHooksOfForwardRef<Props, Ref>(
729752
try {
730753
ancestorStackError = new Error();
731754
renderFunction(props, ref);
755+
} catch (error) {
756+
handleRenderFunctionError(error);
732757
} finally {
733758
readHookLog = hookLog;
734759
hookLog = [];

0 commit comments

Comments
 (0)