I'm trying to create quite a big grid (around 40 col, 1k+ rows - dynamic width) With a sticky header and infinite loader to append more rows. I've used it like in the examples, but when getting more rows performance falls drastically - probably because of dynamic width and cellmeasurer having to check everything. Below is the code for the component I use for printing the table:
import * as React from "react";
import { Grid, CellMeasurer, AutoSizer, ScrollSync, CellMeasurerCache, InfiniteLoader } from 'react-virtualized';
interface VirtualizedTableProps {
loadMore?: (IndexRange: any) => Promise<any>
data: any,
rowHeight?: number,
headerHeight?: number,
headers: string[],
cellClassName?: string,
headerCellClassName?: string,
isFullHeight?: boolean,
getCellContent: Function
}
export class VirtualizedTable extends React.Component<VirtualizedTableProps> {
static defaultProps = {
rowHeight: 37,
headerHeight: 38,
headerCellClassName: 'Virtualized-table-header',
cellClassName: 'Virtualized-table-cell',
isFullHeight: false,
loadMore: () => {},
}
cellMeasurerCache = new CellMeasurerCache({
fixedHeight: true,
minWidth: 40,
//defaultWidth: 40
});
componentDidUpdate(prevProps: VirtualizedTableProps) {
if(prevProps && this.props && prevProps.data !== this.props.data) {
this.cellMeasurerCache.clearAll();
}
}
render() {
const {
rowHeight,
headerHeight,
headers,
cellClassName,
headerCellClassName,
data,
isFullHeight,
loadMore,
getCellContent
} = this.props;
const tableHeight = data.length < 9 ? rowHeight * data.length : rowHeight * 10;
return (
<div style={{ height: '100%' }}>
<ScrollSync>
{({ onScroll, scrollLeft }) => {
return (
<AutoSizer onResize={() => { this.cellMeasurerCache.clearAll() }}>
{({ width, height }) => {
return (
<div>
<Grid
className={'Virtualized-table-header-wrapper'}
columnWidth={this.cellMeasurerCache.columnWidth}
columnCount={headers.length}
deferredMeasurementCache={this.cellMeasurerCache}
height={35}
overscanColumnCount={headers.length}
rowHeight={headerHeight}
rowCount={1}
scrollLeft={scrollLeft}
width={width - 17} // needs to be shorter because of the system scroll
cellRenderer={({ columnIndex, key, parent, rowIndex, style }) => {
const value = headers[columnIndex];
return (
<CellMeasurer
cache={this.cellMeasurerCache}
columnIndex={columnIndex}
key={key}
parent={parent}
rowIndex={rowIndex}
>
<div className={headerCellClassName} style={{
...style,
}}>
<span style={{ padding: '0 20px', whiteSpace: 'nowrap' }}>{value}</span>
</div>
</CellMeasurer>
);
}}
/>
<InfiniteLoader
isRowLoaded={({ index }) => !!data[index]}
loadMoreRows={loadMore}
rowCount={100000000000} // this needs to be like this
>
{({ onRowsRendered, registerChild }) => {
return (
<Grid
onSectionRendered={({ rowStartIndex, rowStopIndex }) => {
const startIndex = rowStartIndex;
const stopIndex = rowStopIndex;
onRowsRendered({ startIndex, stopIndex })
}}
ref={registerChild}
columnCount={headers.length}
columnWidth={this.cellMeasurerCache.columnWidth}
deferredMeasurementCache={this.cellMeasurerCache}
height={isFullHeight ? height - headerHeight : tableHeight }
overscanColumnCount={headers.length}
overscanRowCount={50}
rowHeight={rowHeight}
width={width}
rowCount={data.length}
onScroll={onScroll}
cellRenderer={({ columnIndex, key, parent, rowIndex, style }) => {
const conversation = data[rowIndex];
return (
<CellMeasurer
cache={this.cellMeasurerCache}
columnIndex={columnIndex}
key={key}
parent={parent}
rowIndex={rowIndex+1}
>
<div className={`${cellClassName} ${rowIndex % 2 ? 'even' : ''}`} style={{
...style,
whiteSpace: 'nowrap',
}}>
<span style={{ padding: '0 20px' }}>{getCellContent(conversation, columnIndex)}</span>
</div>
</CellMeasurer>
);
}}
/>
)
}}
</InfiniteLoader>
</div>
)
}}
</AutoSizer>
)
}}
</ScrollSync>
</div>
)
}
}
I'm not sure if I use the cellMeasurer as expected, which may cause the performance drop. Problem is with the sticky header getting out of line when scrolling horizontaly with bigger amount of rows (Not the slow performance of onscroll, it just calculates sticky grids dimensions incorrect):
Maybe I use the cellMeasurer incorrectly? Or some props are set wrong? Anyone had similar problems?