Skip to content

Commit 23f6145

Browse files
author
Asif Ansari
committed
fix: apply getRowId before rows enter internal state store
DataGrid derived effectiveGetRowId but never used it to normalize rows before createInitialState or SET_ROWS keyed them by row.id. Any consumer passing rows without a native id field would silently collapse all rows to the same undefined key in idRowsLookup, producing undefined React keys and a missing-key warning. Normalize activeRows through effectiveGetRowId into normalizedRows (useMemo) immediately after effectiveGetRowId is defined. Pass normalizedRows to useDataGrid and setRows instead of activeRows. No-op per row when the default (row) => row.id is used.
1 parent ba896b1 commit 23f6145

5 files changed

Lines changed: 25 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55

66
---
77

8+
## [1.0.4] — July 30, 2026 🐛
9+
10+
### Fixed
11+
- **`getRowId` not applied to internal row store**: `DataGrid` derived `effectiveGetRowId` correctly but never used it before rows entered the internal state. `createInitialState` and the `SET_ROWS` reducer both indexed by `row.id` directly, so any consumer passing rows without a native `id` field would silently collide all rows on `undefined` in the lookup map, produce `undefined` React keys, and trigger a "Each child in a list should have a unique key prop" warning. Fixed by normalizing `activeRows` through `effectiveGetRowId` into `normalizedRows` (via `useMemo`) immediately after `effectiveGetRowId` is derived. The normalization is a no-op when the default `(row) => row.id` is used, so there is no overhead for the common case.
12+
13+
---
14+
815
## [1.0.3] — July 30, 2026 📚
916

1017
### Fixed

demo/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export default function App() {
135135
<img src={`${import.meta.env.BASE_URL}logo.png`} alt="OpenGridX Logo" className="app-logo" />
136136
<h2 className="app-title">
137137
OpenGridX
138-
<span className="app-version">v1.0.3</span>
138+
<span className="app-version">v1.0.4</span>
139139
</h2>
140140
</div>
141141

demo/Home.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export default function Home(_props: HomeProps) {
6868
<div className="home-logo-hero">
6969
<img src={`${import.meta.env.BASE_URL}banner.png`} alt="OpenGridX Logo" className="home-banner-image" />
7070
</div>
71-
<span className="home-badge">OpenGridX v1.0.3</span>
71+
<span className="home-badge">OpenGridX v1.0.4</span>
7272
<p className="home-subtitle">
7373
The elite, high-performance DataGrid for modern React.
7474
Built to handle massive data with a premium developer experience.

lib/components/DataGrid/DataGrid.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,18 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
202202
const defaultGetRowId = useCallback((row: R) => row.id, []);
203203
const effectiveGetRowId = getRowId || defaultGetRowId;
204204

205+
// Normalize rows so every row has `id === getRowId(row)`.
206+
// createInitialState and SET_ROWS both key the internal store by row.id,
207+
// so rows without a native id field collide on undefined without this.
208+
// When getRowId is the default (row) => row.id this is a no-op per row.
209+
const normalizedRows = useMemo(
210+
() => activeRows.map(row => {
211+
const id = effectiveGetRowId(row);
212+
return id === row.id ? row : ({ ...row, id } as R);
213+
}),
214+
[activeRows, effectiveGetRowId]
215+
);
216+
205217
// Keyboard-mode flag: toggled via DOM classname — no React state needed
206218
// so the ring appears instantly without a re-render cycle.
207219
const setKeyboardMode = useCallback((on: boolean) => {
@@ -226,7 +238,7 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
226238
}, [treeData]);
227239

228240
const gridData = useDataGrid({
229-
rows: activeRows,
241+
rows: normalizedRows,
230242
columns: activeColumns,
231243
rowHeight,
232244
headerHeight,
@@ -358,9 +370,9 @@ export function DataGrid<R extends GridRowModel = GridRowModel>(props: DataGridP
358370

359371
useEffect(() => {
360372
if (!dataSource) {
361-
setRows(activeRows);
373+
setRows(normalizedRows);
362374
}
363-
}, [activeRows, setRows, dataSource]);
375+
}, [normalizedRows, setRows, dataSource]);
364376

365377
// ── Detail panel (hoisted — hasDetailPanel feeds into useGridColumns) ──────
366378
const hasDetailPanel = Boolean(getDetailPanelContent);

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@opencorestack/opengridx",
3-
"version": "1.0.3",
3+
"version": "1.0.4",
44
"description": "OpenGridX: High-performance React data infrastructure. Unlock advanced Row Grouping, Excel Export, and Column Pinning without the usual \"Pro\" gatekeeping. Built for speed, scale, and complete architectural freedom. Fully open, virtualization-ready, and feature-complete.",
55
"type": "module",
66
"main": "./dist/opengridx.umd.js",

0 commit comments

Comments
 (0)