Skip to content

Commit 5a0f486

Browse files
authored
feat(react)!: Drop support for React 16 (#22665)
Removes React 16 support from `@sentry/react` and `@sentry/gatsby` for v11. The minimum supported version is now React 17, as already documented in the v11 migration guide. Raises the `react` peer dependency range and drops two code paths that only existed for React 16. No e2e app targeted React 16 — `react-17` was already the lowest and stays as the app pinning the new minimum. closes #21461
1 parent 3097b9c commit 5a0f486

6 files changed

Lines changed: 7 additions & 46 deletions

File tree

packages/gatsby/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
},
4545
"peerDependencies": {
4646
"gatsby": "^3.0.0 || ^4.0.0 || ^5.0.0",
47-
"react": "16.x || 17.x || 18.x"
47+
"react": "17.x || 18.x"
4848
},
4949
"devDependencies": {
5050
"@testing-library/react": "^15.0.5",

packages/react/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"@sentry/conventions": "^0.16.0"
4242
},
4343
"peerDependencies": {
44-
"react": "^16.14.0 || 17.x || 18.x || 19.x"
44+
"react": "17.x || 18.x || 19.x"
4545
},
4646
"devDependencies": {
4747
"@testing-library/react": "^15.0.5",

packages/react/src/error.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
import { captureException } from '@sentry/browser';
22
import { isError } from '@sentry/core/browser';
33
import type { ErrorInfo } from 'react';
4-
import { version } from 'react';
5-
6-
/**
7-
* See if React major version is 17+ by parsing version string.
8-
*/
9-
export function isAtLeastReact17(reactVersion: string): boolean {
10-
const reactMajor = reactVersion.match(/^([^.]+)/);
11-
return reactMajor !== null && parseInt(reactMajor[0]) >= 17;
12-
}
134

145
/**
156
* Recurse through `error.cause` chain to set cause on an error.
@@ -47,15 +38,14 @@ export function captureReactException(
4738
{ componentStack }: ErrorInfo,
4839
hint?: Parameters<typeof captureException>[1],
4940
): string {
50-
// If on React version >= 17, create stack trace from componentStack param and links
51-
// to to the original error using `error.cause` otherwise relies on error param for stacktrace.
52-
// Linking errors requires the `LinkedErrors` integration be enabled.
41+
// Create a stack trace from the componentStack param and link it to the original error
42+
// using `error.cause`. Linking errors requires the `LinkedErrors` integration be enabled.
5343
// See: https://reactjs.org/blog/2020/08/10/react-v17-rc.html#native-component-stacks
5444
//
5545
// Although `componentDidCatch` is typed to accept an `Error` object, it can also be invoked
5646
// with non-error objects. This is why we need to check if the error is an error-like object.
5747
// See: https://github.com/getsentry/sentry-javascript/issues/6167
58-
if (isAtLeastReact17(version) && isError(error) && componentStack) {
48+
if (isError(error) && componentStack) {
5949
const errorBoundaryError = new Error(error.message);
6050
errorBoundaryError.name = `React ErrorBoundary ${error.name}`;
6151
errorBoundaryError.stack = componentStack;

packages/react/src/hoist-non-react-statics.ts

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,6 @@ const MEMO_STATICS = {
6969
const ForwardRefType = Symbol.for('react.forward_ref');
7070
const MemoType = Symbol.for('react.memo');
7171

72-
/**
73-
* Check if a component is a Memo component
74-
*/
75-
function isMemo(component: unknown): boolean {
76-
return (
77-
typeof component === 'object' && component !== null && (component as { $$typeof?: symbol }).$$typeof === MemoType
78-
);
79-
}
80-
8172
/**
8273
* Map of React component types to their specific statics
8374
*/
@@ -89,12 +80,6 @@ TYPE_STATICS[MemoType] = MEMO_STATICS;
8980
* Get the appropriate statics object for a given component
9081
*/
9182
function getStatics(component: React.ComponentType<unknown>): Record<string, boolean> {
92-
// React v16.11 and below
93-
if (isMemo(component)) {
94-
return MEMO_STATICS;
95-
}
96-
97-
// React v16.12 and above
9883
const componentType = (component as { $$typeof?: symbol }).$$typeof;
9984
return (componentType && TYPE_STATICS[componentType]) || REACT_STATICS;
10085
}

packages/react/src/profiler.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,6 @@ function withProfiler<P extends Record<string, any>>(
177177
*
178178
* `useProfiler` is a React hook that profiles a React component.
179179
*
180-
* Requires React 16.8 or above.
181180
* @param name displayName of component being profiled
182181
*/
183182
function useProfiler(

packages/react/test/error.test.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
11
import * as SentryBrowser from '@sentry/browser';
2-
import { beforeEach, describe, expect, it, test, vi } from 'vitest';
3-
import { isAtLeastReact17, reactErrorHandler } from '../src/error';
4-
5-
describe('isAtLeastReact17', () => {
6-
test.each([
7-
['React 16', '16.0.4', false],
8-
['React 17', '17.0.0', true],
9-
['React 17 with no patch', '17.4', true],
10-
['React 17 with no patch and no minor', '17', true],
11-
['React 18', '18.1.0', true],
12-
['React 19', '19.0.0', true],
13-
])('%s', (_: string, input: string, output: ReturnType<typeof isAtLeastReact17>) => {
14-
expect(isAtLeastReact17(input)).toBe(output);
15-
});
16-
});
2+
import { beforeEach, describe, expect, it, vi } from 'vitest';
3+
import { reactErrorHandler } from '../src/error';
174

185
describe('reactErrorHandler', () => {
196
const captureException = vi.spyOn(SentryBrowser, 'captureException');

0 commit comments

Comments
 (0)