React虚拟化网格+无限加载器+单元测量器

时间:2019-07-19 15:28:25

标签: javascript react-virtualized

我正在尝试创建一个很大的网格(大约40列,超过1k行-动态宽度),并带有粘性标头和无限加载程序以追加更多行。我已经在示例中使用了它,但是当获得更多行时,性能会急剧下降-可能是因为动态宽度和cellmeasurer必须检查所有内容。以下是我用于打印表格的组件的代码:

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>
        )
    }
}

我不确定我是否按预期使用cellMeasurer,这可能会导致性能下降。问题在于,在水平滚动大量行时,粘性标头脱节(不是滚动性能慢,它只是计算出粘性网格的尺寸不正确):

enter image description here

也许我错误地使用了cellMeasurer?还是某些道具设置错误? 任何人都有类似的问题吗?

0 个答案:

没有答案