New May 28, 2026

React DevExtremee - Rows are labeled incorrectly in the DataGrid [closed]

Libraries, Frameworks, etc. All from Newest questions tagged reactjs - Stack Overflow View React DevExtremee - Rows are labeled incorrectly in the DataGrid [closed] on stackoverflow.com

I've added listeners to my app that are supposed to select a row and, when I press Shift + Up or Down Arrow, select the next rows. It works fine until I reach the bottom or top edge, at which point the focus is lost.

I can't load everything at once because we have about 8,000 records in the DataGrid in production; I have to load them using scrolling.mode: virtual.

How can this be handled in DevExtreme?

import React, { useRef, useCallback, useEffect } from 'react';
import DataGrid, {
  Scrolling, Paging, Column, HeaderFilter, Search, Selection,
} from 'devextreme-react/data-grid';
import * as AspNetData from 'devextreme-aspnet-data-nojquery';

const dataSource = AspNetData.createStore({ key: 'Id', loadUrl: 'https://js.devexpress.com/Demos/WidgetsGalleryDataService/api/Sales', });

const App = () => { // Instance gridu - uložená přes onInitialized const gridInstanceRef = useRef<any>(null); const wrapperRef = useRef<HTMLDivElement>(null); const anchorIndexRef = useRef<number | null>(null); const activeIndexRef = useRef<number | null>(null);

const handleInitialized = useCallback((e: any) => { gridInstanceRef.current = e.component; console.log('[Init] grid instance saved:', !!e.component); console.log('[Init] has selectRows:', typeof e.component?.selectRows); console.log('[Init] has getSelectedRowKeys:', typeof e.component?.getSelectedRowKeys); }, []);

const handleRowClick = useCallback((e: any) => { const grid = gridInstanceRef.current; if (!grid) { console.log('[RowClick] no grid'); return; } if (e.rowType !== 'data') return;

const rowIndex = e.rowIndex; const nativeEvent = e.event;

console.log('[RowClick] rowIndex:', rowIndex, 'shift:', nativeEvent?.shiftKey);

if (nativeEvent?.shiftKey && anchorIndexRef.current !== null) { const anchor = anchorIndexRef.current; const start = Math.min(anchor, rowIndex); const end = Math.max(anchor, rowIndex); const keys: any[] = []; for (let i = start; i <= end; i++) { const key = grid.getKeyByRowIndex(i); if (key !== undefined) keys.push(key); } grid.selectRows(keys, false); activeIndexRef.current = rowIndex; } else { // selectRowsByIndexes nemusí existovat - použijeme getKeyByRowIndex + selectRows const key = grid.getKeyByRowIndex(rowIndex); if (key !== undefined) { grid.selectRows([key], false); } anchorIndexRef.current = rowIndex; activeIndexRef.current = rowIndex; } }, []);

useEffect(() => { const wrapper = wrapperRef.current; if (!wrapper) return;

const onKeyDown = (event: KeyboardEvent) => { if (!event.shiftKey) return; if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return;

const grid = gridInstanceRef.current; if (!grid) { console.log('[KeyDown] no grid instance'); return; }

const target = event.target as HTMLElement; if (!wrapper.contains(target)) return; const tag = target?.tagName; if (tag === 'INPUT' || tag === 'TEXTAREA' || target?.isContentEditable) return;

// Zastav DŘÍV než DX naviguje event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation();

// Resolve anchor if (anchorIndexRef.current === null) { const selected = grid.getSelectedRowKeys(); console.log('[KeyDown] anchor null, selected:', selected); if (selected && selected.length > 0) { const idx = grid.getRowIndexByKey(selected[0]); if (idx >= 0) { anchorIndexRef.current = idx; activeIndexRef.current = idx; } } else { const focused = grid.option('focusedRowIndex'); if (typeof focused === 'number' && focused >= 0) { anchorIndexRef.current = focused; activeIndexRef.current = focused; } else { console.log('[KeyDown] no anchor available'); return; } } }

let active = activeIndexRef.current ?? anchorIndexRef.current!; active = event.key === 'ArrowDown' ? active + 1 : active - 1;

const totalCount = grid.totalCount(); if (active < 0) active = 0; if (totalCount >= 0 && active >= totalCount) active = totalCount - 1;

activeIndexRef.current = active;

const anchor = anchorIndexRef.current!; const start = Math.min(anchor, active); const end = Math.max(anchor, active);

console.log('[KeyDown] anchor:', anchor, 'active:', active, 'range:', start, '-', end);

const keys: any[] = []; for (let i = start; i <= end; i++) { const k = grid.getKeyByRowIndex(i); if (k !== undefined) keys.push(k); }

console.log('[KeyDown] keys to select:', keys.length);

if (keys.length > 0) { grid.selectRows(keys, false); const cell = grid.getCellElement(active, 0); if (cell) { grid.focus(cell); } } };

document.addEventListener('keydown', onKeyDown, true); return () => { document.removeEventListener('keydown', onKeyDown, true); }; }, []);

return ( <div ref={wrapperRef}> <DataGrid height={440} dataSource={dataSource} showBorders={true} remoteOperations={true} wordWrapEnabled={true} onInitialized={handleInitialized} onRowClick={handleRowClick} > <Selection mode="multiple" showCheckBoxesMode="none" /> <Scrolling mode="virtual" rowRenderingMode="virtual" /> <Paging defaultPageSize={100} /> <HeaderFilter visible={true}> <Search enabled={true} /> </HeaderFilter> <Column dataField="Id" width={90} /> <Column dataField="StoreName" caption="Store" width={150} /> <Column dataField="ProductCategoryName" caption="Category" width={120} /> <Column dataField="ProductName" caption="Product" /> <Column dataField="DateKey" caption="Date" dataType="date" format="yyyy-MM-dd" width={110} /> <Column dataField="SalesAmount" caption="Amount" format="currency" width={100}> <HeaderFilter groupInterval={1000} /> </Column> </DataGrid> </div> ); };

export default App;

Scroll to top