Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* 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 strict
*/

module.exports = {
showErrorDialog: jest.fn(),
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ module.exports = {
get BatchedBridge() {
return require('./BatchedBridge.js');
},
get ExceptionsManager() {
return require('./ExceptionsManager');
},
get Platform() {
return require('./Platform');
},
get RCTEventEmitter() {
return require('./RCTEventEmitter');
},
get ReactFiberErrorDialog() {
return require('./ReactFiberErrorDialog');
},
get ReactNativeViewConfigRegistry() {
return require('./ReactNativeViewConfigRegistry');
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,14 @@
import type {CapturedError} from '../ReactCapturedValue';

// Module provided by RN:
import {ExceptionsManager} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {ReactFiberErrorDialog as RNImpl} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import invariant from 'shared/invariant';

/**
* Intercept lifecycle errors and ensure they are shown with the correct stack
* trace within the native redbox component.
*/
export function showErrorDialog(capturedError: CapturedError): boolean {
const {componentStack, error} = capturedError;

let errorToHandle: Error;

// Typically Errors are thrown but eg strings or null can be thrown as well.
if (error instanceof Error) {
const {message, name} = error;
invariant(
typeof RNImpl.showErrorDialog === 'function',
'Expected ReactFiberErrorDialog.showErrorDialog to be a function.',
);

const summary = message ? `${name}: ${message}` : name;

errorToHandle = error;

try {
errorToHandle.message = `${summary}\n\nThis error is located at:${componentStack}`;
} catch (e) {}
} else if (typeof error === 'string') {
errorToHandle = new Error(
`${error}\n\nThis error is located at:${componentStack}`,
);
} else {
errorToHandle = new Error(`Unspecified error at:${componentStack}`);
}

ExceptionsManager.handleException(errorToHandle, false);

// Return false here to prevent ReactFiberErrorLogger default behavior of
// logging error details to console.error. Calls to console.error are
// automatically routed to the native redbox controller, which we've already
// done above by calling ExceptionsManager.
return false;
export function showErrorDialog(capturedError: CapturedError): boolean {
return RNImpl.showErrorDialog(capturedError);
}
5 changes: 3 additions & 2 deletions scripts/flow/react-native-host-hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
ViewConfigGetter,
} from 'react-native-renderer/src/ReactNativeTypes';
import type {RNTopLevelEventType} from 'events/TopLevelEventTypes';
import type {CapturedError} from 'react-reconciler/src/ReactCapturedValue';

declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface' {
declare export function deepDiffer(one: any, two: any): boolean;
Expand All @@ -29,8 +30,8 @@ declare module 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface'
blurTextInput: (object: any) => void,
focusTextInput: (object: any) => void,
};
declare export var ExceptionsManager: {
handleException: (error: Error, isFatal: boolean) => void,
declare export var ReactFiberErrorDialog: {
showErrorDialog: (error: CapturedError) => boolean,
};
declare export var Platform: {
OS: string,
Expand Down