Skip to content

Commit 1538948

Browse files
Drop support for React 18 (#3503)
* React 19 * beta -> rc * remove patch script * -forwardRef * use ComponentProps * import useLayoutEffect directly * use contexts directly * fix lint * cleanup useRef type * add missing exports * use stable React 19 * provider -> context * -1 forwardRef * add forceConsistentCasingInFileNames * bump * remove reference to old vitest.workspace.ts * update deps * remove unnecessary RefAttributes * fix types * apply same fix to TreeDataGrid * update chromium issue links * remove unused ref --------- Co-authored-by: Aman Mahajan <amahajan@stratag.com> Co-authored-by: Aman Mahajan <amahajan@freewheel.tv>
1 parent 1abde2f commit 1538948

33 files changed

Lines changed: 166 additions & 246 deletions

.github/workflows/ci.yml

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,12 @@ on:
88
jobs:
99
test:
1010
runs-on: ubuntu-latest
11-
strategy:
12-
matrix:
13-
react: [18, 19]
14-
fail-fast: false
1511
steps:
1612
- uses: actions/checkout@v4
1713
- uses: actions/setup-node@v4
1814
with:
1915
node-version: 23
2016
check-latest: true
21-
- name: set up react 19
22-
if: matrix.react == 19
23-
run: |
24-
node ./.github/workflows/patch-react19.js
25-
cat package.json
2617
- name: npm install
2718
run: npm i
2819
- name: Biome
@@ -45,12 +36,11 @@ jobs:
4536
run: node --run test
4637
timeout-minutes: 4
4738
- name: Upload coverage
48-
if: matrix.react == 18
4939
uses: codecov/codecov-action@v5
5040
with:
5141
token: ${{ secrets.CODECOV_TOKEN }}
5242
- name: Deploy gh-pages
53-
if: matrix.react == 18 && github.event_name == 'push' && github.ref == 'refs/heads/main'
43+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
5444
run: |
5545
git config --global user.email 'action@github.com'
5646
git config --global user.name 'GitHub Action'

.github/workflows/patch-react19.js

Lines changed: 0 additions & 15 deletions
This file was deleted.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
## Features
2020

21-
- [React 18.0+](package.json) support
21+
- [React 19.0+](package.json) support
2222
- [Evergreen browsers and server-side rendering](browserslist) support
2323
- Tree-shaking support and only [one npm dependency](package.json) to keep your bundles slim
2424
- Great performance thanks to virtualization: columns and rows outside the viewport are not rendered
@@ -42,7 +42,7 @@
4242
- [Cell copy / pasting](https://adazzle.github.io/react-data-grid/#/AllFeatures)
4343
- [Cell value dragging / filling](https://adazzle.github.io/react-data-grid/#/AllFeatures)
4444
- [Customizable Renderers](https://adazzle.github.io/react-data-grid/#/CustomizableRenderers)
45-
- Right-to-left (RTL) support. We recommend using Firefox as Chrome has a [bug](https://bugs.chromium.org/p/chromium/issues/detail?id=1140374) with frozen columns.
45+
- Right-to-left (RTL) support. We recommend using Firefox as Chrome has a [bug](https://issues.chromium.org/issues/40653832) with frozen columns.
4646

4747
## Links
4848

@@ -419,16 +419,16 @@ interface Renderers<TRow, TSummaryRow> {
419419
}
420420
```
421421

422-
For example, the default `<Row />` component can be wrapped via the `renderRow` prop to add context providers or tweak props
422+
For example, the default `<Row />` component can be wrapped via the `renderRow` prop to add contexts or tweak props
423423

424424
```tsx
425425
import DataGrid, { RenderRowProps, Row } from 'react-data-grid';
426426

427427
function myRowRenderer(key: React.Key, props: RenderRowProps<Row>) {
428428
return (
429-
<MyContext.Provider key={key} value={123}>
429+
<MyContext key={key} value={123}>
430430
<Row {...props} />
431-
</MyContext.Provider>
431+
</MyContext>
432432
);
433433
}
434434

eslint.config.js

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -564,11 +564,6 @@ export default [
564564
importNames: ['default'],
565565
message: 'Use named imports instead.'
566566
},
567-
{
568-
name: 'react',
569-
importNames: ['useLayoutEffect'],
570-
message: 'Use the override from src/hooks instead.'
571-
},
572567
{
573568
name: 'react-dom',
574569
importNames: ['default'],

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@
6969
"@testing-library/react": "^16.2.0",
7070
"@testing-library/user-event": "^14.5.2",
7171
"@types/node": "^22.12.0",
72-
"@types/react": "^18.3.9",
73-
"@types/react-dom": "^18.3.0",
72+
"@types/react": "^19.0.8",
73+
"@types/react-dom": "^19.0.3",
7474
"@typescript-eslint/eslint-plugin": "^8.22.0",
7575
"@typescript-eslint/parser": "^8.22.0",
7676
"@vitejs/plugin-react": "^4.3.4",
@@ -93,10 +93,10 @@
9393
"playwright": "^1.50.0",
9494
"postcss": "^8.5.1",
9595
"prettier": "3.5.0",
96-
"react": "^18.3.1",
96+
"react": "^19.0.0",
9797
"react-dnd": "^16.0.1",
9898
"react-dnd-html5-backend": "^16.0.1",
99-
"react-dom": "^18.3.1",
99+
"react-dom": "^19.0.0",
100100
"rolldown": "^1.0.0-beta.3",
101101
"typescript": "~5.7.3",
102102
"vite": "^6.0.11",

src/Cell.tsx

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { forwardRef, memo, type RefAttributes } from 'react';
1+
import { memo } from 'react';
22
import { css } from '@linaria/core';
33

44
import { useRovingTabIndex } from './hooks';
@@ -25,26 +25,23 @@ const cellDraggedOver = css`
2525

2626
const cellDraggedOverClassname = `rdg-cell-dragged-over ${cellDraggedOver}`;
2727

28-
function Cell<R, SR>(
29-
{
30-
column,
31-
colSpan,
32-
isCellSelected,
33-
isCopied,
34-
isDraggedOver,
35-
row,
36-
rowIdx,
37-
className,
38-
onClick,
39-
onDoubleClick,
40-
onContextMenu,
41-
onRowChange,
42-
selectCell,
43-
style,
44-
...props
45-
}: CellRendererProps<R, SR>,
46-
ref: React.Ref<HTMLDivElement>
47-
) {
28+
function Cell<R, SR>({
29+
column,
30+
colSpan,
31+
isCellSelected,
32+
isCopied,
33+
isDraggedOver,
34+
row,
35+
rowIdx,
36+
className,
37+
onClick,
38+
onDoubleClick,
39+
onContextMenu,
40+
onRowChange,
41+
selectCell,
42+
style,
43+
...props
44+
}: CellRendererProps<R, SR>) {
4845
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellSelected);
4946

5047
const { cellClass } = column;
@@ -101,7 +98,6 @@ function Cell<R, SR>(
10198
aria-colspan={colSpan}
10299
aria-selected={isCellSelected}
103100
aria-readonly={!isEditable || undefined}
104-
ref={ref}
105101
tabIndex={tabIndex}
106102
className={className}
107103
style={{
@@ -126,9 +122,7 @@ function Cell<R, SR>(
126122
);
127123
}
128124

129-
const CellComponent = memo(forwardRef(Cell)) as <R, SR>(
130-
props: CellRendererProps<R, SR> & RefAttributes<HTMLDivElement>
131-
) => React.JSX.Element;
125+
const CellComponent = memo(Cell) as <R, SR>(props: CellRendererProps<R, SR>) => React.JSX.Element;
132126

133127
export default CellComponent;
134128

src/DataGrid.tsx

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1-
import { forwardRef, useCallback, useImperativeHandle, useMemo, useRef, useState } from 'react';
2-
import type { Key, KeyboardEvent, RefAttributes } from 'react';
1+
import {
2+
useCallback,
3+
useImperativeHandle,
4+
useLayoutEffect,
5+
useMemo,
6+
useRef,
7+
useState
8+
} from 'react';
9+
import type { Key, KeyboardEvent } from 'react';
310
import { flushSync } from 'react-dom';
411
import clsx from 'clsx';
512

613
import {
7-
HeaderRowSelectionChangeProvider,
8-
HeaderRowSelectionProvider,
9-
RowSelectionChangeProvider,
14+
HeaderRowSelectionChangeContext,
15+
HeaderRowSelectionContext,
16+
RowSelectionChangeContext,
1017
useCalculatedColumns,
1118
useColumnWidths,
1219
useGridDimensions,
1320
useLatestFunc,
14-
useLayoutEffect,
1521
useViewportColumns,
1622
useViewportRows,
1723
type HeaderRowSelectionContextValue
@@ -55,9 +61,9 @@ import type {
5561
import { defaultRenderCell } from './Cell';
5662
import { renderCheckbox as defaultRenderCheckbox } from './cellRenderers';
5763
import {
58-
DataGridDefaultRenderersProvider,
64+
DataGridDefaultRenderersContext,
5965
useDefaultRenderers
60-
} from './DataGridDefaultRenderersProvider';
66+
} from './DataGridDefaultRenderersContext';
6167
import DragHandle from './DragHandle';
6268
import EditCell from './EditCell';
6369
import GroupedColumnHeaderRow from './GroupedColumnHeaderRow';
@@ -97,7 +103,7 @@ export interface DataGridHandle {
97103
}
98104

99105
type SharedDivProps = Pick<
100-
React.HTMLAttributes<HTMLDivElement>,
106+
React.ComponentProps<'div'>,
101107
| 'role'
102108
| 'aria-label'
103109
| 'aria-labelledby'
@@ -109,6 +115,7 @@ type SharedDivProps = Pick<
109115
>;
110116

111117
export interface DataGridProps<R, SR = unknown, K extends Key = Key> extends SharedDivProps {
118+
ref?: Maybe<React.Ref<DataGridHandle>>;
112119
/**
113120
* Grid and data Props
114121
*/
@@ -215,11 +222,11 @@ export interface DataGridProps<R, SR = unknown, K extends Key = Key> extends Sha
215222
*
216223
* <DataGrid columns={columns} rows={rows} />
217224
*/
218-
function DataGrid<R, SR, K extends Key>(
219-
props: DataGridProps<R, SR, K>,
220-
ref: React.Ref<DataGridHandle>
225+
export default function DataGrid<R, SR = unknown, K extends Key = Key>(
226+
props: DataGridProps<R, SR, K>
221227
) {
222228
const {
229+
ref,
223230
// Grid and data Props
224231
columns: rawColumns,
225232
rows,
@@ -1125,9 +1132,9 @@ function DataGrid<R, SR, K extends Key>(
11251132
data-testid={testId}
11261133
data-cy={dataCy}
11271134
>
1128-
<DataGridDefaultRenderersProvider value={defaultGridComponents}>
1129-
<HeaderRowSelectionChangeProvider value={selectHeaderRowLatest}>
1130-
<HeaderRowSelectionProvider value={headerSelectionValue}>
1135+
<DataGridDefaultRenderersContext value={defaultGridComponents}>
1136+
<HeaderRowSelectionChangeContext value={selectHeaderRowLatest}>
1137+
<HeaderRowSelectionContext value={headerSelectionValue}>
11311138
{Array.from({ length: groupedColumnHeaderRowsCount }, (_, index) => (
11321139
<GroupedColumnHeaderRow
11331140
key={index}
@@ -1155,8 +1162,8 @@ function DataGrid<R, SR, K extends Key>(
11551162
shouldFocusGrid={!selectedCellIsWithinSelectionBounds}
11561163
direction={direction}
11571164
/>
1158-
</HeaderRowSelectionProvider>
1159-
</HeaderRowSelectionChangeProvider>
1165+
</HeaderRowSelectionContext>
1166+
</HeaderRowSelectionChangeContext>
11601167
{rows.length === 0 && noRowsFallback ? (
11611168
noRowsFallback
11621169
) : (
@@ -1184,9 +1191,9 @@ function DataGrid<R, SR, K extends Key>(
11841191
/>
11851192
);
11861193
})}
1187-
<RowSelectionChangeProvider value={selectRowLatest}>
1194+
<RowSelectionChangeContext value={selectRowLatest}>
11881195
{getViewportRows()}
1189-
</RowSelectionChangeProvider>
1196+
</RowSelectionChangeContext>
11901197
{bottomSummaryRows?.map((row, rowIdx) => {
11911198
const gridRowStart = headerAndTopSummaryRowsCount + rows.length + rowIdx + 1;
11921199
const summaryRowIdx = rows.length + rowIdx;
@@ -1219,7 +1226,7 @@ function DataGrid<R, SR, K extends Key>(
12191226
})}
12201227
</>
12211228
)}
1222-
</DataGridDefaultRenderersProvider>
1229+
</DataGridDefaultRenderersContext>
12231230

12241231
{renderDragHandle()}
12251232

@@ -1262,7 +1269,3 @@ function getCellToScroll(gridEl: HTMLDivElement) {
12621269
function isSamePosition(p1: Position, p2: Position) {
12631270
return p1.idx === p2.idx && p1.rowIdx === p2.rowIdx;
12641271
}
1265-
1266-
export default forwardRef(DataGrid) as <R, SR = unknown, K extends Key = Key>(
1267-
props: DataGridProps<R, SR, K> & RefAttributes<DataGridHandle>
1268-
) => React.JSX.Element;
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,7 @@ import { createContext, useContext } from 'react';
33
import type { Maybe, Renderers } from './types';
44

55
// eslint-disable-next-line @typescript-eslint/no-explicit-any
6-
const DataGridDefaultRenderersContext = createContext<Maybe<Renderers<any, any>>>(undefined);
7-
8-
export const DataGridDefaultRenderersProvider = DataGridDefaultRenderersContext.Provider;
6+
export const DataGridDefaultRenderersContext = createContext<Maybe<Renderers<any, any>>>(undefined);
97

108
export function useDefaultRenderers<R, SR>(): Maybe<Renderers<R, SR>> {
119
return useContext(DataGridDefaultRenderersContext);

src/DragHandle.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,14 @@ const cellDragHandleFrozenClassname = css`
3232

3333
const cellDragHandleClassname = `rdg-cell-drag-handle ${cellDragHandle}`;
3434

35-
// TODO: replace with RefObject once we drop support for React 18
36-
interface LatestDraggedOverRowIdxRef {
37-
readonly current: number | undefined;
38-
}
39-
4035
interface Props<R, SR> extends Pick<DataGridProps<R, SR>, 'rows' | 'onRowsChange'> {
4136
gridRowStart: number;
4237
column: CalculatedColumn<R, SR>;
4338
columnWidth: number | string;
4439
maxColIdx: number;
4540
isLastRow: boolean;
4641
selectedPosition: SelectCellState;
47-
latestDraggedOverRowIdx: LatestDraggedOverRowIdxRef;
42+
latestDraggedOverRowIdx: React.RefObject<number | undefined>;
4843
isCellEditable: (position: Position) => boolean;
4944
onClick: () => void;
5045
onFill: (event: FillEvent<R>) => R;

src/EditCell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export default function EditCell<R, SR>({
5656
onKeyDown,
5757
navigate
5858
}: EditCellProps<R, SR>) {
59-
const frameRequestRef = useRef<number | undefined>(undefined);
59+
const frameRequestRef = useRef<number>(undefined);
6060
const commitOnOutsideClick = column.editorOptions?.commitOnOutsideClick !== false;
6161

6262
// We need to prevent the `useEffect` from cleaning up between re-renders,

0 commit comments

Comments
 (0)