Row Models

Choose client, infinite, or server-side row data.

Wit Grid supports three row model modes, chosen with the rowModelType prop (default 'client'):

client

Rows are already in memory; the grid owns local sort/filter work.

infinite

Rows load in block ranges as the user scrolls; sort/filter state is sent to the datasource.

server

The server owns range loading plus route, grouping, sort, filter, and query state.

Client Rows

Client mode is the default. Pass rows directly.

<Grid rows={rows} columns={columns} getRowId={(row) => row.id} />

Use client mode for small to medium datasets, local editing, and application flows where the full row array is already in memory.

Infinite Rows

Infinite mode loads row blocks by numeric range.

import type { InfiniteDatasource } from '@witbybit/wit-grid-react';

type Order = {
	id: string;
	customer: string;
	total: number;
};

const datasource: InfiniteDatasource<Order> = {
	async getRows(params, { signal }) {
		const url = new URL('/api/orders', location.origin);
		url.searchParams.set('start', String(params.startRow));
		url.searchParams.set('end', String(params.endRow));
		url.searchParams.set('sort', JSON.stringify(params.sortModel));
		url.searchParams.set('filter', JSON.stringify(params.filter));

		const response = await fetch(url, { signal });
		if (!response.ok) throw new Error('Failed to load orders');
		return response.json();
	},
};

<Grid rowModelType='infinite' columns={columns} datasource={datasource} blockSize={100} getRowId={(row) => row.id} />;

The datasource receives:

Request FieldNotes
startRowInclusive start index.
endRowExclusive end index.
sortModelCurrent sort state.
filterThe grid's filter: { columns, search, query } (each null when unset).

Return:

type InfiniteGetRowsResult<TRowData> = {
	rows: TRowData[];
	totalCount?: number;
	lastRow?: number;
	hasMore?: boolean;
};

Use one of totalCount, lastRow, or hasMore to tell the grid whether more rows exist. The grid validates duplicate ids and inconsistent row counts.

Server-Side Rows

Server mode uses a richer request shape for stores, routes, grouping metadata, and server-owned query behavior.

import type { ServerSideDatasource } from '@witbybit/wit-grid-react';

const datasource: ServerSideDatasource<Order> = {
	async getRows(request, { signal }) {
		const response = await fetch('/api/orders/query', {
			method: 'POST',
			signal,
			headers: { 'content-type': 'application/json' },
			body: JSON.stringify(request),
		});

		if (!response.ok) throw new Error('Failed to load orders');
		return response.json();
	},
};

<Grid rowModelType='server' columns={columns} datasource={datasource} blockSize={100} getRowId={(row) => row.id} />;

The server request contains:

Request FieldNotes
startRow / endRowRequested range. endRow is exclusive.
routeStore route. Empty route means the root store.
groupKeysGroup keys for the current route.
rowGroupColumnsGroup column metadata.
valueColumnsAggregated value column metadata.
sortModelCurrent sort state or null.
filterThe grid's filter: { columns, search, query } (each null when unset).

Return:

type ServerSideGetRowsResult<TRowData> = {
	rows: readonly TRowData[];
	rowCount?: number;
	lastRow?: number;
	hasMore?: boolean;
	aggregateData?: Readonly<Record<string, unknown>>;
	groupMetadata?: readonly ServerSideGroupMetadata[];
};

Use rowCount, lastRow, or hasMore to describe the row count state. Server mode also accepts aggregateData and groupMetadata for grouped stores.

Refreshing Datasources

Use the API from onGridReady to replace or refresh server-owned data.

<Grid
	rowModelType='server'
	columns={columns}
	datasource={datasource}
	onGridReady={({ api }) => {
		api.refreshServerSide();
	}}
/>

For infinite mode, use api.setInfiniteDatasource(nextDatasource, blockSize). For server mode, use api.setServerSideDatasource(nextDatasource), api.refreshServerSide(), or api.purgeServerSide().

Events

Async row models emit lifecycle events, and a server-side grid's loading state is followed with watch:

ListenMode
api.on(GridEventName.infiniteBlockLoaded)Infinite
api.on(GridEventName.infiniteBlockLoadFailed)Infinite
api.watch((grid) => grid.status.serverSide)Server

See Events for generated event payloads.

Selection Scope

Selection is bounded by what is loaded

Infinite and server-side row models operate on loaded data. Selection scopes such as "all rows" (see Selection) only apply to rows that are loaded or represented by the current model capability — not the full remote dataset.

Edit on GitHub

Last updated on

On this page