mirror of
https://github.com/facebook/react.git
synced 2026-02-27 03:07:57 +00:00
89 lines
3.5 KiB
JavaScript
89 lines
3.5 KiB
JavaScript
/**
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*
|
|
* @flow
|
|
*/
|
|
|
|
import type {CapturedError} from './ReactCapturedValue';
|
|
|
|
import {showErrorDialog} from './ReactFiberErrorDialog';
|
|
|
|
export function logCapturedError(capturedError: CapturedError): void {
|
|
const logError = showErrorDialog(capturedError);
|
|
|
|
// Allow injected showErrorDialog() to prevent default console.error logging.
|
|
// This enables renderers like ReactNative to better manage redbox behavior.
|
|
if (logError === false) {
|
|
return;
|
|
}
|
|
|
|
const error = (capturedError.error: any);
|
|
if (__DEV__) {
|
|
const {
|
|
componentName,
|
|
componentStack,
|
|
errorBoundaryName,
|
|
errorBoundaryFound,
|
|
willRetry,
|
|
} = capturedError;
|
|
|
|
// Browsers support silencing uncaught errors by calling
|
|
// `preventDefault()` in window `error` handler.
|
|
// We record this information as an expando on the error.
|
|
if (error != null && error._suppressLogging) {
|
|
if (errorBoundaryFound && willRetry) {
|
|
// The error is recoverable and was silenced.
|
|
// Ignore it and don't print the stack addendum.
|
|
// This is handy for testing error boundaries without noise.
|
|
return;
|
|
}
|
|
// The error is fatal. Since the silencing might have
|
|
// been accidental, we'll surface it anyway.
|
|
// However, the browser would have silenced the original error
|
|
// so we'll print it first, and then print the stack addendum.
|
|
console.error(error);
|
|
// For a more detailed description of this block, see:
|
|
// https://github.com/facebook/react/pull/13384
|
|
}
|
|
|
|
const componentNameMessage = componentName
|
|
? `The above error occurred in the <${componentName}> component:`
|
|
: 'The above error occurred in one of your React components:';
|
|
|
|
let errorBoundaryMessage;
|
|
// errorBoundaryFound check is sufficient; errorBoundaryName check is to satisfy Flow.
|
|
if (errorBoundaryFound && errorBoundaryName) {
|
|
if (willRetry) {
|
|
errorBoundaryMessage =
|
|
`React will try to recreate this component tree from scratch ` +
|
|
`using the error boundary you provided, ${errorBoundaryName}.`;
|
|
} else {
|
|
errorBoundaryMessage =
|
|
`This error was initially handled by the error boundary ${errorBoundaryName}.\n` +
|
|
`Recreating the tree from scratch failed so React will unmount the tree.`;
|
|
}
|
|
} else {
|
|
errorBoundaryMessage =
|
|
'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
|
|
'Visit https://fb.me/react-error-boundaries to learn more about error boundaries.';
|
|
}
|
|
const combinedMessage =
|
|
`${componentNameMessage}${componentStack}\n\n` +
|
|
`${errorBoundaryMessage}`;
|
|
|
|
// In development, we provide our own message with just the component stack.
|
|
// We don't include the original error message and JS stack because the browser
|
|
// has already printed it. Even if the application swallows the error, it is still
|
|
// displayed by the browser thanks to the DEV-only fake event trick in ReactErrorUtils.
|
|
console.error(combinedMessage);
|
|
} else {
|
|
// In production, we print the error directly.
|
|
// This will include the message, the JS stack, and anything the browser wants to show.
|
|
// We pass the error object instead of custom message so that the browser displays the error natively.
|
|
console.error(error);
|
|
}
|
|
}
|