Skip to content

Performance

Optimize grid performance for large datasets and high-frequency updates.

The grid automatically virtualizes when row count exceeds 100.

  1. Only visible rows are rendered to the DOM
  2. Scroll position determines which rows to show
  3. Buffer rows above/below viewport for smooth scrolling
// Always virtualize (even small datasets)
<DataGrid virtualize={true} ... />
// Never virtualize
<DataGrid virtualize={false} ... />
// Auto (default) - virtualize when rows > 100
<DataGrid virtualize="auto" ... />

For accurate virtualization, specify row height:

<DataGrid
rowHeight={32} // Default: 36
...
/>

Install the optional WASM core for maximum performance:

Terminal window
npm install @askturret/grid-wasm
OperationJavaScriptWASM
Sort 100k rows~180ms5ms
Filter 100k rows~80ms<1ms
Aggregations~100ms10ms

The grid automatically uses WASM when available:

// No code changes needed
// Grid detects and uses WASM core if installed

For explicit control:

import { initWasm } from '@askturret/grid';
// Initialize WASM early (e.g., app startup)
await initWasm();

Flash detection only runs for visible rows, not the entire dataset.

Flash effects automatically disable when FPS drops:

  • Disables at 55 FPS
  • Re-enables at 58 FPS
  • Prevents performance degradation during heavy updates

For maximum performance:

<DataGrid disableFlash ... />

Tested on AMD Ryzen, Linux, Chrome 131:

Row CountRender Time
1,00012ms
10,00045ms
100,00052ms
1,000,00068ms
Row CountSort Time
10,0002ms
100,0005ms
1,000,00018ms
Row CountFilter Time
10,000<1ms
100,000<1ms
1,000,000<2ms
Update RateFPS Maintained
100 rows/sec60 FPS
1,000 rows/sec60 FPS
10,000 rows/sec55+ FPS
// Good - stable, unique key
<DataGrid rowKey="id" ... />
// Bad - index as key (breaks optimization)
<DataGrid rowKey={(row, index) => index} ... />
// Good - columns don't change reference
const columns = useMemo(() => [
{ field: 'name', header: 'Name' },
{ field: 'price', header: 'Price' },
], []);
// Bad - new array every render
<DataGrid columns={[
{ field: 'name', header: 'Name' },
]} ... />
// Good - single state update
setData(prev => {
const updated = [...prev];
updates.forEach(update => {
const index = updated.findIndex(r => r.id === update.id);
if (index >= 0) updated[index] = { ...updated[index], ...update };
});
return updated;
});
// Bad - multiple state updates
updates.forEach(update => {
setData(prev => prev.map(r =>
r.id === update.id ? { ...r, ...update } : r
));
});
// Good - new object reference
setData(prev => prev.map(row =>
row.id === id ? { ...row, price: newPrice } : row
));
// Bad - mutation
data.find(r => r.id === id).price = newPrice;
setData([...data]);
import { throttle } from 'lodash';
const updateData = throttle((updates) => {
setData(prev => applyUpdates(prev, updates));
}, 100); // Max 10 updates per second

For complex filters, filter before passing to grid:

const filteredData = useMemo(() => {
return allData.filter(row => {
// Complex filter logic
return row.status === status && row.price > minPrice;
});
}, [allData, status, minPrice]);
<DataGrid data={filteredData} ... />
Row CountMemory Usage
10,000~15 MB
100,000~80 MB
1,000,000~400 MB
  1. Limit columns: Only include necessary fields
  2. Use compact mode: Smaller row height = less DOM
  3. Paginate if needed: For 1M+ rows, consider pagination
  1. Open React DevTools Profiler
  2. Record during interaction
  3. Look for unnecessary re-renders
// Measure sort time
performance.mark('sort-start');
// ... sort operation
performance.mark('sort-end');
performance.measure('sort', 'sort-start', 'sort-end');
const measure = performance.getEntriesByName('sort')[0];
console.log(`Sort took ${measure.duration}ms`);

The grid includes an internal FPS monitor for adaptive mode. Access it for debugging:

import { useAdaptiveFlash } from '@askturret/grid';
function DebugPanel() {
const { enabled, fps } = useAdaptiveFlash();
return <div>FPS: {fps}, Flash: {enabled ? 'on' : 'off'}</div>;
}