import type {Fiber, FiberRoot} from './ReactInternalTypes';
import type {CapturedValue} from './ReactCapturedValue';
import getComponentNameFromFiber from 'react-reconciler/src/getComponentNameFromFiber';
import {ClassComponent} from './ReactWorkTags';
import reportGlobalError from 'shared/reportGlobalError';
import ReactSharedInternals from 'shared/ReactSharedInternals';
const {ReactCurrentActQueue} = ReactSharedInternals;
let componentName: null | string = null;
let errorBoundaryName: null | string = null;
export function defaultOnUncaughtError(
error: mixed,
errorInfo: {+componentStack?: ?string},
): void {
reportGlobalError(error);
if (__DEV__) {
const componentStack =
errorInfo.componentStack != null ? errorInfo.componentStack : '';
const componentNameMessage = componentName
? `An error occurred in the <${componentName}> component:`
: 'An error occurred in one of your React components:';
console['warn'](
'%s\n%s\n\n%s',
componentNameMessage,
componentStack || '',
'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
'Visit https://react.dev/link/error-boundaries to learn more about error boundaries.',
);
}
}
export function defaultOnCaughtError(
error: mixed,
errorInfo: {
+componentStack?: ?string,
+errorBoundary?: ?React$Component<any, any>,
},
): void {
if (__DEV__) {
const componentStack =
errorInfo.componentStack != null ? errorInfo.componentStack : '';
const componentNameMessage = componentName
? `The above error occurred in the <${componentName}> component:`
: 'The above error occurred in one of your React components:';
console['error'](
'%o\n\n%s\n%s\n\n%s',
error,
componentNameMessage,
componentStack,
`React will try to recreate this component tree from scratch ` +
`using the error boundary you provided, ${
errorBoundaryName || 'Anonymous'
}.`,
);
} else {
console['error'](error);
}
}
export function defaultOnRecoverableError(
error: mixed,
errorInfo: {+digest?: ?string, +componentStack?: ?string},
) {
reportGlobalError(error);
}
export function logUncaughtError(
root: FiberRoot,
errorInfo: CapturedValue<mixed>,
): void {
try {
if (__DEV__) {
componentName = errorInfo.source
? getComponentNameFromFiber(errorInfo.source)
: null;
errorBoundaryName = null;
}
const error = (errorInfo.value: any);
if (__DEV__ && ReactCurrentActQueue.current !== null) {
ReactCurrentActQueue.thrownErrors.push(error);
return;
}
const onUncaughtError = root.onUncaughtError;
onUncaughtError(error, {
componentStack: errorInfo.stack,
});
} catch (e) {
setTimeout(() => {
throw e;
});
}
}
export function logCaughtError(
root: FiberRoot,
boundary: Fiber,
errorInfo: CapturedValue<mixed>,
): void {
try {
if (__DEV__) {
componentName = errorInfo.source
? getComponentNameFromFiber(errorInfo.source)
: null;
errorBoundaryName = getComponentNameFromFiber(boundary);
}
const error = (errorInfo.value: any);
const onCaughtError = root.onCaughtError;
onCaughtError(error, {
componentStack: errorInfo.stack,
errorBoundary:
boundary.tag === ClassComponent
? boundary.stateNode
: null,
});
} catch (e) {
setTimeout(() => {
throw e;
});
}
}