Skip to content

Commit 454893f

Browse files
author
Jonathan Como
authored
fix(react): Require ReactElement in ErrorBoundary props and render (#3857)
Updates the ErrorBoundary fallback type in @sentry/react to require a ReactElement, which matches the `React.isValidElement` check better.
1 parent 9ca4c5b commit 454893f

File tree

2 files changed

+27
-9
lines changed

2 files changed

+27
-9
lines changed

packages/react/src/errorboundary.tsx

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
withScope,
99
} from '@sentry/browser';
1010
import { Event } from '@sentry/types';
11-
import { parseSemver } from '@sentry/utils';
11+
import { logger, parseSemver } from '@sentry/utils';
1212
import hoistNonReactStatics from 'hoist-non-react-statics';
1313
import * as React from 'react';
1414

@@ -21,7 +21,7 @@ export type FallbackRender = (errorData: {
2121
componentStack: string | null;
2222
eventId: string | null;
2323
resetError(): void;
24-
}) => React.ReactNode;
24+
}) => React.ReactElement;
2525

2626
export type ErrorBoundaryProps = {
2727
/** If a Sentry report dialog should be rendered on error */
@@ -39,7 +39,7 @@ export type ErrorBoundaryProps = {
3939
* the error, the component stack, and an function that resets the error boundary on error.
4040
*
4141
*/
42-
fallback?: React.ReactNode | FallbackRender;
42+
fallback?: React.ReactElement | FallbackRender;
4343
/** Called with the error boundary encounters an error */
4444
onError?(error: Error, componentStack: string, eventId: string): void;
4545
/** Called on componentDidMount() */
@@ -160,14 +160,22 @@ class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundarySta
160160
const { error, componentStack, eventId } = this.state;
161161

162162
if (error) {
163-
if (React.isValidElement(fallback)) {
164-
return fallback;
165-
}
163+
let element: React.ReactElement | undefined = undefined;
166164
if (typeof fallback === 'function') {
167-
return fallback({ error, componentStack, resetError: this.resetErrorBoundary, eventId }) as FallbackRender;
165+
element = fallback({ error, componentStack, resetError: this.resetErrorBoundary, eventId });
166+
} else {
167+
element = fallback;
168+
}
169+
170+
if (React.isValidElement(element)) {
171+
return element;
172+
}
173+
174+
if (fallback) {
175+
logger.warn('fallback did not produce a valid ReactElement');
168176
}
169177

170-
// Fail gracefully if no fallback provided
178+
// Fail gracefully if no fallback provided or is not valid
171179
return null;
172180
}
173181

packages/react/test/errorboundary.test.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,17 @@ describe('ErrorBoundary', () => {
8080

8181
it('renders null if not given a valid `fallback` prop', () => {
8282
const { container } = render(
83-
<ErrorBoundary fallback={new Error('true')}>
83+
<ErrorBoundary fallback="Not a ReactElement">
84+
<Bam />
85+
</ErrorBoundary>,
86+
);
87+
88+
expect(container.innerHTML).toBe('');
89+
});
90+
91+
it('renders null if not given a valid `fallback` prop function', () => {
92+
const { container } = render(
93+
<ErrorBoundary fallback={() => 'Not a ReactElement'}>
8494
<Bam />
8595
</ErrorBoundary>,
8696
);

0 commit comments

Comments
 (0)