Data Sources
Client-side and server-side data handling
Data Sources
gp-grid provides a flexible data source abstraction for both client-side and server-side data handling.
Basic Usage with rowData
The simplest approach is using the rowData prop directly:
const data = [
{ id: 1, name: "Giovanni" },
{ id: 2, name: "Luca" },
];
<Grid columns={columns} rowData={data} rowHeight={36} />This internally creates a client data source.
Client Data Source
For more control, use createClientDataSource:
import { Grid, createClientDataSource } from "gp-grid-react";
const data = generateLargeDataset(1000000);
const dataSource = createClientDataSource(data);
<Grid columns={columns} dataSource={dataSource} rowHeight={36} />Options
interface ClientDataSourceOptions<TData> {
getFieldValue?: (row: TData, field: string) => CellValue;
useWorker?: boolean;
}| Option | Default | Description |
|---|---|---|
getFieldValue | - | Custom accessor for nested properties |
useWorker | true | Use Web Worker for sorting large datasets |
Nested Properties
const data = [
{ id: 1, user: { name: "Giovanni", email: "g@example.com" } },
];
const dataSource = createClientDataSource(data, {
getFieldValue: (row, field) => {
if (field === "userName") return row.user.name;
if (field === "userEmail") return row.user.email;
return row[field as keyof typeof row];
},
});Mutable Data Source
For CRUD operations and real-time data updates, use createMutableClientDataSource. This data source is backed by a robust transaction system that enables efficient batching and optimistic updates.
import { createMutableClientDataSource } from "gp-grid-react";
const dataSource = createMutableClientDataSource(data, {
getRowId: (row) => row.id, // Required: unique ID accessor
debounceMs: 50, // Batch updates (default: 50)
});
// Add rows
dataSource.addRows([{ id: 3, name: "Mario" }]);
// Remove rows
dataSource.removeRows([1, 2]);
// Update a cell
dataSource.updateCell(3, "name", "Maria");
// Update a row
dataSource.updateRow(3, { name: "Maria", email: "maria@example.com" });
// Force immediate processing
await dataSource.flushTransactions();Transaction System
The mutable data source uses an internal transaction system that provides several key benefits:
Automatic Batching - Multiple operations within the debounce window are combined into a single transaction, minimizing re-renders and improving performance.
Optimistic Processing - Changes are queued and processed asynchronously, allowing the UI to remain responsive during bulk operations.
Transaction Callbacks - Track when transactions are processed:
const dataSource = createMutableClientDataSource(data, {
getRowId: (row) => row.id,
debounceMs: 50,
onTransactionProcessed: (result) => {
console.log(`Added: ${result.added}, Removed: ${result.removed}`);
// Update external state, analytics, etc.
},
});Flush Control - Force immediate processing when needed:
// Wait for all pending transactions
await dataSource.flushTransactions();
// Check if there are pending changes
if (dataSource.hasPendingTransactions()) {
// Handle pending state
}Options
interface MutableClientDataSourceOptions<TData> {
getRowId: (row: TData) => RowId; // Required: unique ID accessor
debounceMs?: number; // Batch window (default: 50)
getFieldValue?: (row: TData, field: string) => CellValue;
onTransactionProcessed?: (result: TransactionResult) => void;
}
interface TransactionResult {
added: number; // Count of rows added
removed: number; // Count of rows removed
updated: number; // Count of rows updated
}MutableDataSource Interface
interface MutableDataSource<TData> extends DataSource<TData> {
addRows(rows: TData[]): void;
removeRows(ids: RowId[]): void;
updateCell(id: RowId, field: string, value: CellValue): void;
updateRow(id: RowId, data: Partial<TData>): void;
flushTransactions(): Promise<void>;
hasPendingTransactions(): boolean;
getDistinctValues(field: string): CellValue[];
getRowById(id: RowId): TData | undefined;
getTotalRowCount(): number;
subscribe(listener: DataChangeListener): () => void;
}Use Cases
The mutable data source is ideal for:
- Real-time dashboards - Live data feeds with frequent updates
- Streaming data - WebSocket or SSE data streams
- User editing - Forms and inline editing with immediate feedback
- Bulk operations - Import, batch updates, mass delete
See the Live Data example for a complete implementation.
Server Data Source
For server-side sorting, filtering, and pagination:
import { createServerDataSource } from "gp-grid-react";
const dataSource = createServerDataSource(async (request) => {
const { pagination, sort, filter } = request;
const response = await fetch("/api/data", {
method: "POST",
body: JSON.stringify({
page: pagination.pageIndex,
pageSize: pagination.pageSize,
sortBy: sort,
filters: filter,
}),
});
const result = await response.json();
return {
rows: result.data,
totalRows: result.total,
};
});
<Grid columns={columns} dataSource={dataSource} rowHeight={36} />Request Interface
interface DataSourceRequest {
pagination: {
pageIndex: number;
pageSize: number;
};
sort?: SortModel[];
filter?: FilterModel;
}Response Interface
interface DataSourceResponse<TData> {
rows: TData[];
totalRows: number;
}Choosing a Data Source
| Scenario | Recommended |
|---|---|
| Small dataset (under 10k rows) | rowData prop |
| Large dataset, client-side | createClientDataSource |
| Editable data with CRUD | createMutableClientDataSource |
| Server-side operations | createServerDataSource |