使用antd的table来渲染大量数据的表格,例如:一个货品有n个子货品,子货品里面有多个商品规格,导致一页20条数据会显示多出多倍的数量的数据。
1. 使用场景:为什么 antd Table 会卡?
展示的表格有 两层结构:
- 第一层:数据(20行)
- 第二层:每个数据有 100 个子数据(共 2000 行数据)
假设你用 antd Table 直接渲染,会遇到以下问题:
-
DOM 渲染负担大:
- 直接渲染 2000 行,每行 10 列,就会生成 2 万个 DOM 节点,导致页面卡顿。
-
React 重新渲染次数多:
- 如果修改一项数据(例如调整某个子数据的数量),
antd Table可能导致整个表格重新渲染,而不是仅更新受影响的部分。
- 如果修改一项数据(例如调整某个子数据的数量),
-
展开/折叠性能差:
- 数据展开时,
antd需要动态更新子行的expandedRowRender,如果数据量大,可能会导致 UI 卡死。
- 数据展开时,
2. 优化思路:为什么改用 ali-react-table
在深入分析 antd Table 的问题后,我评估了 ali-react-table,发现它的优化点刚好能解决我的问题:
| 问题 | antd Table | ali-react-table |
|---|---|---|
| 大数据渲染 | 直接渲染所有数据,DOM 过多,导致页面卡顿 | 虚拟滚动,只渲染视口内的行,显著减少 DOM |
| 展开/折叠性能 | 重新计算 expandedRowRender,影响整个表格 | 数据扁平化,展开时只影响局部数据 |
| 列宽适配 | 复杂表头计算列宽时容易导致回流 | 列宽预计算,减少浏览器回流 |
| 响应式优化 | 数据变化会触发大量 render | useMemo+useCallback 只更新受影响的部分 |
3. ali-react-table 如何解决你的问题?
(1) 虚拟滚动优化:减少 DOM 渲染
核心原理:
- 仅渲染可视区域的行,不渲染未出现在视口中的数据,类似于
React Window。 translateY+ 绝对定位 来模拟滚动,使得滚动流畅。
代码示例:
<BaseTable
columns={columns}
dataSource={data}
useVirtual={true} // 开启虚拟滚动
estimatedRowHeight={40} // 预估行高,避免滚动抖动
rowKey="id"
/>
总结:
antd Table一次性渲染 2000 行,页面会卡顿;ali-react-table只渲染可视区域,例如 首屏 20 行,其他行在滚动时动态加载,从而显著提升性能。
(2) 数据扁平化优化:展开时减少计算
核心原理:
ali-react-table采用 一次性扁平化处理数据,避免每次expand都递归计算。
代码示例:
const treeData = buildTreeHierarchy(originalData, row => row.parentId);
<BaseTable
columns={columns}
dataSource={treeData}
primaryKey="id"
isTree={true} // 关键:启用树形结构优化
defaultExpandedRowKeys={[]} // 默认折叠,减少初始渲染负担
/>
总结:
antd每次展开都会重新递归计算子项,展开 100 行就会导致 React 执行大量setState。ali-react-table直接把数据展平为扁平数组,展开时只是更新visibleRows,不会影响其他数据,从而加速展开速度。
(3) Memoization 记忆化计算:减少重复渲染
核心原理:
useMemo只计算 受影响的部分,防止render过度触发。
代码示例:
const memoizedColumns = useMemo(() => generateColumns(), []);
const memoizedData = useMemo(() => formatData(dataSource), [dataSource]);
<BaseTable columns={memoizedColumns} dataSource={memoizedData} />
总结:
antd Table默认是 全局重新渲染,修改一个规格的库存,整张表都要rerender。ali-react-table只重新计算受影响的数据,避免无意义的重新渲染。
ali-react-table 处理大数据量表格,优化了表格渲染性能,掌握了其核心机制,包括虚拟滚动、列宽自适应、数据扁平化处理、Memoization 以及分批渲染,提升了表格交互的流畅度,并减少了不必要的渲染开销。
1. 虚拟滚动(Virtual Scrolling)
-
实现方式:
-
只渲染可视区域的数据,利用
translateY来调整行的位置,避免一次性创建大量 DOM 节点。 -
核心代码位于
useVirtual.ts,其中:visibleCount = Math.ceil(containerHeight / rowHeight) + overscan计算可视范围的行数。- 监听
onScroll事件动态更新startIndex,只渲染startIndex → endIndex的行。
-
-
解释
- 就像微信聊天记录,往上滑才会加载更多,而不是一次性全部加载。
2. 数据扁平化处理
-
实现方式:
- 树形数据(如多级表头、嵌套行)会提前进行扁平化存储,避免每次
render()递归计算,提高索引速度。 - 主要逻辑在
buildRowHierarchy方法中,展开/折叠时仅更新受影响的行,而不是重新计算整个数据集。
- 树形数据(如多级表头、嵌套行)会提前进行扁平化存储,避免每次
-
解释
- 类似于 Vue 的
computed,提前算好扁平结构,避免每次操作时都重新计算。
- 类似于 Vue 的
3. 列宽自适应优化
-
实现方式:
-
ali-react-table在autoWidth模式下,会:- 优先渲染列头
- 计算实际宽度
- 再调整列宽
-
这样可以减少回流(reflow),避免因表格布局计算导致页面卡顿。
-
-
解释
- 就像 Excel 自动调整列宽,先看最长内容,然后再调整布局。
4. Memoization 记忆化计算
-
实现方式:
-
在
ali-react-table里,useMemo和useCallback被大量使用:getVisibleRows用useMemo避免重复计算当前可见数据。useEvent避免onScroll事件频繁重新绑定。
-
-
解释
- 相当于 React 里的
React.memo(),只有数据变化时才重新计算,避免无意义的渲染。
- 相当于 React 里的
5. 分批渲染(Batch Rendering)
-
实现方式:
ali-react-table采用requestAnimationFrame让 React 先渲染关键内容,再逐步渲染剩余的部分,避免主线程阻塞。
-
解释
- 像网页图片懒加载,先显示模糊图,后面再加载高清图。
总结
ali-react-table主要依赖 虚拟滚动、数据扁平化、列宽优化、Memoization 和分批渲染 来提升性能。例如,它会只渲染可视区域的行,并且提前计算好数据结构,减少不必要的 DOM 操作。此外,它还会利用 requestAnimationFrame 让关键内容优先渲染,从而保证流畅度。
-
虚拟滚动的实现方式?
- 解释
translateY和onScroll如何动态渲染行。
- 解释
-
表格如何减少回流?
- 说明列宽计算策略 + 避免不必要的 DOM 更新。
-
Memoization 在表格里的应用?
- 提及
useMemo、useCallback的作用。
- 提及