Master Detail - Caching Detail DataGrid
By far the most common scenario will be to render another DataGrid in the detail row.
For such cases we offer a caching mechanism that will keep the state of the detail DataGrid when the user collapses and then expands the row again.
The most important part of the state of detail DataGrid that will be cached is the data-related.
More specifically, when cached, the detail
<DataSource />
will get its data from the cache and will not call the data
function when mounted.Other persisted parts of the state are the sorting, filtering and grouping information.
To enable caching, use the
rowDetailCache
prop.It can be one of the following:
false
- caching is disabled - this is the defaulttrue
- enables caching for all detail DataGridsnumber
- the maximum number of detail DataGrids to keep in the cache. When the limit is reached, the oldest detail DataGrid will be removed from the cache.
This example will cache the last 5 detail DataGrids - meaning they won't reload when you expand them again.
You can try collapsing a row and then expanding it again to see the caching in action - it won't reload the data.
But when you open up a row that hasn't been opened before, it will load the data from the remote location.
View Mode
Fork Forkimport * as React from 'react'; import { DataSourceData, InfiniteTable, InfiniteTablePropColumns, DataSource, InfiniteTableRowInfo, } from '@infinite-table/infinite-react'; type Developer = { id: number; firstName: string; lastName: string; city: string; currency: string; country: string; preferredLanguage: string; stack: string; canDesign: 'yes' | 'no'; salary: number; }; type City = { id: number; name: string; country: string; }; const masterColumns: InfiniteTablePropColumns<City> = { id: { field: 'id', header: 'ID', defaultWidth: 70, renderRowDetailIcon: true, }, country: { field: 'country', header: 'Country' }, city: { field: 'name', header: 'City', defaultFlex: 1 }, }; const detailColumns: InfiniteTablePropColumns<Developer> = { firstName: { field: 'firstName', header: 'First Name', }, salary: { field: 'salary', type: 'number', }, stack: { field: 'stack' }, currency: { field: 'currency' }, city: { field: 'city' }, }; const domProps = { style: { height: '100%', }, }; const shouldReloadData = { sortInfo: true, filterValue: true, }; function renderDetail(rowInfo: InfiniteTableRowInfo<City>) { console.log('rendering detail for master row', rowInfo.id); return ( <DataSource<Developer> data={detailDataSource} primaryKey="id" shouldReloadData={shouldReloadData} > <InfiniteTable<Developer> columnDefaultWidth={150} columnMinWidth={50} columns={detailColumns} /> </DataSource> ); } const defaultRowDetailState = { collapsedRows: true as const, expandedRows: [39, 54], }; export default () => { return ( <> <DataSource<City> data={citiesDataSource} primaryKey="id" defaultSortInfo={[ { field: 'country', dir: 1, }, { field: 'name', dir: 1, }, ]} > <InfiniteTable<City> domProps={domProps} columnDefaultWidth={150} defaultRowDetailState={defaultRowDetailState} columnMinWidth={50} columns={masterColumns} rowDetailCache={5} rowDetailHeight={200} rowDetailRenderer={renderDetail} /> </DataSource> </> ); }; // fetch an array of cities from the server const citiesDataSource: DataSourceData<City> = () => { const cityNames = new Set<string>(); const result: City[] = []; return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers1k-sql`) .then((response) => response.json()) .then((response) => { response.data.forEach((data: Developer) => { if (cityNames.has(data.city)) { return; } cityNames.add(data.city); result.push({ name: data.city, country: data.country, id: result.length, }); }); return result; }); }; const detailDataSource: DataSourceData<Developer> = ({ filterValue, sortInfo, masterRowInfo, }) => { if (sortInfo && !Array.isArray(sortInfo)) { sortInfo = [sortInfo]; } if (!filterValue) { filterValue = []; } if (masterRowInfo) { // filter by master country and city filterValue = [ { field: 'city', filter: { operator: 'eq', type: 'string', value: masterRowInfo.data.name, }, }, { field: 'country', filter: { operator: 'eq', type: 'string', value: masterRowInfo.data.country, }, }, ...filterValue, ]; } const args = [ sortInfo ? 'sortInfo=' + JSON.stringify( sortInfo.map((s) => ({ field: s.field, dir: s.dir, })), ) : null, filterValue ? 'filterBy=' + JSON.stringify( filterValue.map(({ field, filter }) => { return { field: field, operator: filter.operator, value: filter.type === 'number' ? Number(filter.value) : filter.value, }; }), ) : null, ] .filter(Boolean) .join('&'); return fetch('https://infinite-table.com/.netlify/functions/json-server' + `/developers1k-sql?` + args) .then((r) => r.json()) .then( (data: Developer[]) => new Promise((resolve) => { setTimeout(() => { resolve(data); }, 500)