mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Store throws a specific Error type (UnsupportedBridgeOperationError) (#24147)
When this Error type is detected, DevTools shows a custom error overlay with upgrade/downgrade instructions.
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
export default class UnsupportedBridgeOperationError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
|
||||
// Maintains proper stack trace for where our error was thrown (only available on V8)
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, UnsupportedBridgeOperationError);
|
||||
}
|
||||
|
||||
this.name = 'UnsupportedBridgeOperationError';
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -44,6 +44,7 @@ import type {
|
||||
FrontendBridge,
|
||||
BridgeProtocol,
|
||||
} from 'react-devtools-shared/src/bridge';
|
||||
import UnsupportedBridgeOperationError from 'react-devtools-shared/src/UnsupportedBridgeOperationError';
|
||||
|
||||
const debug = (methodName, ...args) => {
|
||||
if (__DEBUG__) {
|
||||
@@ -1252,7 +1253,9 @@ export default class Store extends EventEmitter<{|
|
||||
break;
|
||||
default:
|
||||
this._throwAndEmitError(
|
||||
Error(`Unsupported Bridge operation "${operation}"`),
|
||||
new UnsupportedBridgeOperationError(
|
||||
`Unsupported Bridge operation "${operation}"`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+20
-1
@@ -10,10 +10,12 @@
|
||||
import * as React from 'react';
|
||||
import {Component, Suspense} from 'react';
|
||||
import Store from 'react-devtools-shared/src/devtools/store';
|
||||
import UnsupportedBridgeOperationView from './UnsupportedBridgeOperationView';
|
||||
import ErrorView from './ErrorView';
|
||||
import SearchingGitHubIssues from './SearchingGitHubIssues';
|
||||
import SuspendingErrorView from './SuspendingErrorView';
|
||||
import TimeoutView from './TimeoutView';
|
||||
import UnsupportedBridgeOperationError from 'react-devtools-shared/src/UnsupportedBridgeOperationError';
|
||||
import TimeoutError from 'react-devtools-shared/src/TimeoutError';
|
||||
import {logEvent} from 'react-devtools-shared/src/Logger';
|
||||
|
||||
@@ -30,6 +32,7 @@ type State = {|
|
||||
componentStack: string | null,
|
||||
errorMessage: string | null,
|
||||
hasError: boolean,
|
||||
isUnsupportedBridgeOperationError: boolean,
|
||||
isTimeout: boolean,
|
||||
|};
|
||||
|
||||
@@ -39,6 +42,7 @@ const InitialState: State = {
|
||||
componentStack: null,
|
||||
errorMessage: null,
|
||||
hasError: false,
|
||||
isUnsupportedBridgeOperationError: false,
|
||||
isTimeout: false,
|
||||
};
|
||||
|
||||
@@ -54,6 +58,8 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
: null;
|
||||
|
||||
const isTimeout = error instanceof TimeoutError;
|
||||
const isUnsupportedBridgeOperationError =
|
||||
error instanceof UnsupportedBridgeOperationError;
|
||||
|
||||
const callStack =
|
||||
typeof error === 'object' &&
|
||||
@@ -69,6 +75,7 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
callStack,
|
||||
errorMessage,
|
||||
hasError: true,
|
||||
isUnsupportedBridgeOperationError,
|
||||
isTimeout,
|
||||
};
|
||||
}
|
||||
@@ -102,6 +109,7 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
componentStack,
|
||||
errorMessage,
|
||||
hasError,
|
||||
isUnsupportedBridgeOperationError,
|
||||
isTimeout,
|
||||
} = this.state;
|
||||
|
||||
@@ -117,6 +125,14 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
errorMessage={errorMessage}
|
||||
/>
|
||||
);
|
||||
} else if (isUnsupportedBridgeOperationError) {
|
||||
return (
|
||||
<UnsupportedBridgeOperationView
|
||||
callStack={callStack}
|
||||
componentStack={componentStack}
|
||||
errorMessage={errorMessage}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ErrorView
|
||||
@@ -125,7 +141,10 @@ export default class ErrorBoundary extends Component<Props, State> {
|
||||
dismissError={
|
||||
canDismissProp || canDismissState ? this._dismissError : null
|
||||
}
|
||||
errorMessage={errorMessage}>
|
||||
errorMessage={errorMessage}
|
||||
isUnsupportedBridgeOperationError={
|
||||
isUnsupportedBridgeOperationError
|
||||
}>
|
||||
<Suspense fallback={<SearchingGitHubIssues />}>
|
||||
<SuspendingErrorView
|
||||
callStack={callStack}
|
||||
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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 * as React from 'react';
|
||||
import styles from './shared.css';
|
||||
|
||||
type Props = {|
|
||||
callStack: string | null,
|
||||
children: React$Node,
|
||||
componentStack: string | null,
|
||||
errorMessage: string | null,
|
||||
|};
|
||||
|
||||
export default function UnsupportedBridgeOperationView({
|
||||
callStack,
|
||||
children,
|
||||
componentStack,
|
||||
errorMessage,
|
||||
}: Props) {
|
||||
return (
|
||||
<div className={styles.ErrorBoundary}>
|
||||
{children}
|
||||
<div className={styles.ErrorInfo}>
|
||||
<div className={styles.HeaderRow}>
|
||||
<div className={styles.ErrorHeader}>
|
||||
{errorMessage || 'Bridge protocol mismatch'}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.InfoBox}>
|
||||
An incompatible version of <code>react-devtools-core</code> has been
|
||||
embedded in a renderer like React Native. To fix this, update the{' '}
|
||||
<code>react-devtools-core</code> package within the React Native
|
||||
application, or downgrade the <code>react-devtools</code> package you
|
||||
use to open the DevTools UI.
|
||||
</div>
|
||||
{!!callStack && (
|
||||
<div className={styles.ErrorStack}>
|
||||
The error was thrown {callStack.trim()}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -121,4 +121,13 @@
|
||||
|
||||
.CloseButtonIcon {
|
||||
margin-left: 0.25rem;
|
||||
}
|
||||
|
||||
.InfoBox {
|
||||
margin-top: 0.5rem;
|
||||
background: var(--color-console-warning-background);
|
||||
border: 1px solid var(--color-console-warning-border);
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 0.5rem;
|
||||
color: var(--color-console-warning-text);
|
||||
}
|
||||
Reference in New Issue
Block a user