Antd Table+react-window实现表格单页展示大量数据

3,544 阅读3分钟

背景

用过antd table的可能会发现当设置单页显示200条以上数据的时候,无论是点击分页栏切换下一页,还是进行全选或取消全选功能,都会变得明显卡顿,当然这里的明显因人而异。 用一张图来展示效果: table_1.png

这是当表格单页展示了500条数据并点击复选框进行全选时的性能截图,可以看到左下方饼图里,整个全选过程花费了6684ms,接近7秒的时间。就,还挺卡的。

寻找解决方案

带着疑问打开了antd官网,找到Table组件。哎呦,不错哦~看到了“虚拟列表”四个字,似乎是官方提供的解决方案,那就来看看吧。“虚拟列表”方案的主要思想,是把Table组件的body部分用react-window的虚拟列表组件进行覆盖,以达到徒有Table其表但内里是虚拟列表的“两手都抓”的准备。Table组件理所应当的给我们准备了components属性:

image.png

既然方案都有了,那就照着官网开始改造自己的代码吧~

首先,引入相应组件:

import { VariableSizeGrid as Gridfrom 'react-window';

接着,将components的body覆盖:

components={{
    body: renderVirtualList
}}
//摘去了一些代码
const renderVirtualList = (rawData, {scrollbarSize,ref,onScroll})=>{
    return (
        <Grid
            columnWidth={index=>mergedColumns[index].width} //宽度要设置或计算好
            columnCount={mergedColumns.length}
            rowCount={rawData.length}
            rowHeight={54}
            width={1000} //根据实际需要,或和官网一样监听屏幕尺寸计算
        >
            {({columnIndex,rowIndex,style})=>(
                <div style={style}> //style必须要有,不然滚动会出现白屏
                     {{rawData[rowIndex][mergedColumns[columnIndex].dataIndex]}}
                </div>
            )}
        </Grid>
    )
}

官网的rawData是[1,2,3,4,5,...,99999,100000]这样一个数组,表格展示的是数组的索引,而实际开发中表格展示的可能是文字、可能是图标。这样的话该怎么写呢?可以从columns入手。在使用Table组件时,一般做法就是先定义好columns数组,columns数组里可以通过render函数定义每一个单元格的渲染方式,所以我们只需要调用一下这个方法即可:

{columns[columnIndex].render(rawData[rowIndex][columns[columnIndex].dataIndex], rawData[rowIndex])}

这样就可以看到和修改前一样的表格内容了。

处理勾选列

“等等,我的表格里第一页明明是复选框列,修改后怎么没啦?”

是的。由于表格的body项是一整个被重写了,所以原来开箱既有的rowSelection中定义的效果都失效了。这时我们只能动动小手自己往上加了。笔者的笨方法还是通过columns下手,但实际components属性还提供了其他属性(见:其他)用来修改表格的其他部位,但是笔者这时已经满足了业务需要,就没有再继续探索了...所以,嗯:将columns第一列设置成:

{
   title: <Checkbox onChange={handleCheckAll} checked={xxx} indeterminate={xxx}/>
   dataIndex: 'id',
   render:(value,record)=><Checkbox onChange={e=>handleCheck(e,value,record)} checked={xxx}/>

}

通过将首列和首列的标题都渲染成复选框,可以进行勾选操作。 经过一步步改造,最后可以收获一个单页展示500条数据,但是也不卡顿的表格了~

其他

贴下components的其他属性:

export interface TableComponents<RecordType> {  
    table?: CustomizeComponent;  
    header?: { 
        wrapper?: CustomizeComponent; 
        row?: CustomizeComponent;
        cell?: CustomizeComponent;
    }; 
    body?: CustomizeScrollBody<RecordType> ||
           {
               wrapper?: CustomizeComponent; 
               row?: CustomizeComponent; 
               cell?: CustomizeComponent;
            }; 
}