Skip to content

Commit

Permalink
[ReactDebugTools] wrap uncaught error from rendering user's component
Browse files Browse the repository at this point in the history
  • Loading branch information
mondaychen committed Mar 28, 2022
1 parent 60cb32b commit dad75d3
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 1 deletion.
11 changes: 11 additions & 0 deletions packages/react-debug-tools/src/ReactDebugCustomErrors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

export const ErrorsNames = {
UNSUPPORTTED_FEATURE_ERROR: 'UnsupportedFeatureError',
RENDER_FUNCTION_ERROR: 'RenderFunctionError',
};

// For now we just override the name. If we decide to move react-debug-tools to
Expand All @@ -25,3 +26,13 @@ export function createUnsupportedFeatureError(message: string = '') {
error.name = ErrorsNames.UNSUPPORTTED_FEATURE_ERROR;
return error;
}

export function createRenderFunctionError(
message: string = '',
options: Object = {},
) {
// $FlowFixMe: Flow doesn't know about 2nd argument of Error constructor
const error = new Error(message, options);
error.name = ErrorsNames.RENDER_FUNCTION_ERROR;
return error;
}
27 changes: 26 additions & 1 deletion packages/react-debug-tools/src/ReactDebugHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ import {
ContextProvider,
ForwardRef,
} from 'react-reconciler/src/ReactWorkTags';
import {createUnsupportedFeatureError} from './ReactDebugCustomErrors';
import {
createUnsupportedFeatureError,
createRenderFunctionError,
ErrorsNames,
} from './ReactDebugCustomErrors';

type CurrentDispatcherRef = typeof ReactSharedInternals.ReactCurrentDispatcher;

Expand Down Expand Up @@ -666,6 +670,23 @@ function processDebugValues(
}
}

function handleRenderFunctionError(error: any): void {
// original error might be any type.
const isError = error instanceof Error;
if (isError && error.name === ErrorsNames.UNSUPPORTTED_FEATURE_ERROR) {
throw error;
}
// If the error is not caused by an unsupported feature, it means
// that the error is caused by user's code in renderFunction.
// In this case, we should wrap the original error inside a custom error
// so that devtools can show a clear message for it.
const messgae: string =
isError && error.message
? error.message
: 'Error rendering inspected component';
throw createRenderFunctionError(messgae, {cause: error});
}

export function inspectHooks<Props>(
renderFunction: Props => React$Node,
props: Props,
Expand All @@ -685,6 +706,8 @@ export function inspectHooks<Props>(
try {
ancestorStackError = new Error();
renderFunction(props);
} catch (error) {
handleRenderFunctionError(error);
} finally {
readHookLog = hookLog;
hookLog = [];
Expand Down Expand Up @@ -729,6 +752,8 @@ function inspectHooksOfForwardRef<Props, Ref>(
try {
ancestorStackError = new Error();
renderFunction(props, ref);
} catch (error) {
handleRenderFunctionError(error);
} finally {
readHookLog = hookLog;
hookLog = [];
Expand Down

0 comments on commit dad75d3

Please sign in to comment.