ali-react-table 处理大数据量表格

583 阅读5分钟

使用antd的table来渲染大量数据的表格,例如:一个货品有n个子货品,子货品里面有多个商品规格,导致一页20条数据会显示多出多倍的数量的数据。

1. 使用场景:为什么 antd Table 会卡?

展示的表格有 两层结构

  • 第一层:数据(20行)
  • 第二层:每个数据有 100 个子数据(共 2000 行数据)

假设你用 antd Table 直接渲染,会遇到以下问题:

  1. DOM 渲染负担大

    • 直接渲染 2000 行,每行 10 列,就会生成 2 万个 DOM 节点,导致页面卡顿。
  2. React 重新渲染次数多

    • 如果修改一项数据(例如调整某个子数据的数量),antd Table 可能导致整个表格重新渲染,而不是仅更新受影响的部分。
  3. 展开/折叠性能差

    • 数据展开时,antd 需要动态更新子行的 expandedRowRender,如果数据量大,可能会导致 UI 卡死。

2. 优化思路:为什么改用 ali-react-table

在深入分析 antd Table 的问题后,我评估了 ali-react-table,发现它的优化点刚好能解决我的问题:

问题antd Tableali-react-table
大数据渲染直接渲染所有数据,DOM 过多,导致页面卡顿虚拟滚动,只渲染视口内的行,显著减少 DOM
展开/折叠性能重新计算 expandedRowRender,影响整个表格数据扁平化,展开时只影响局部数据
列宽适配复杂表头计算列宽时容易导致回流列宽预计算,减少浏览器回流
响应式优化数据变化会触发大量 renderuseMemo+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,提前算好扁平结构,避免每次操作时都重新计算。

3. 列宽自适应优化

  • 实现方式

    • ali-react-tableautoWidth 模式下,会:

      1. 优先渲染列头
      2. 计算实际宽度
      3. 再调整列宽
    • 这样可以减少回流(reflow),避免因表格布局计算导致页面卡顿。

  • 解释

    • 就像 Excel 自动调整列宽,先看最长内容,然后再调整布局。

4. Memoization 记忆化计算

  • 实现方式

    • ali-react-table 里,useMemouseCallback 被大量使用:

      • getVisibleRowsuseMemo 避免重复计算当前可见数据。
      • useEvent 避免 onScroll 事件频繁重新绑定。
  • 解释

    • 相当于 React 里的 React.memo(),只有数据变化时才重新计算,避免无意义的渲染。

5. 分批渲染(Batch Rendering)

  • 实现方式

    • ali-react-table 采用 requestAnimationFrame 让 React 先渲染关键内容,再逐步渲染剩余的部分,避免主线程阻塞。
  • 解释

    • 像网页图片懒加载,先显示模糊图,后面再加载高清图。

总结

ali-react-table 主要依赖 虚拟滚动、数据扁平化、列宽优化、Memoization 和分批渲染 来提升性能。例如,它会只渲染可视区域的行,并且提前计算好数据结构,减少不必要的 DOM 操作。此外,它还会利用 requestAnimationFrame 让关键内容优先渲染,从而保证流畅度。

  1. 虚拟滚动的实现方式?

    • 解释 translateYonScroll 如何动态渲染行。
  2. 表格如何减少回流?

    • 说明列宽计算策略 + 避免不必要的 DOM 更新。
  3. Memoization 在表格里的应用?

    • 提及 useMemouseCallback 的作用。