You need to enable JavaScript to run this app. react-virtualized Table渲染性能差、滚动点击后卡顿如何优化?
优惠活动
大模型
产品
解决方案
定价
更多

react-virtualized Table渲染性能差、滚动点击后卡顿如何优化?

React Virtualized Table 性能优化方案

一、现有代码的核心问题

当前卡顿的核心原因是大量不必要的重渲染:所有渲染函数内的回调、配置对象都是内联生成的,每次父组件更新都会生成新的引用,触发Table、Column组件递归重渲染,滚动时频繁更新的状态会进一步放大这个问题。

二、基础优化(无需修改渲染逻辑)

先完成以下优化,90%的场景下可以解决卡顿问题:

  • 所有回调函数用useCallback做引用固化,避免每次渲染生成新函数
    // 组件内部提前封装所有回调
    const headerRenderer = useCallback(({dataKey}) => headersConfig[dataKey].content, [headersConfig])
    const cellRenderer = useCallback(({ cellData }) => cellData, [])
    const rowGetter = useCallback(({ index }) => getRowRow(index), [getRowRow])
    const rowClassName = useCallback(getRowClassName, [getRowClassName])
    const noRowsRenderer = useCallback(noRowsRendererHandler, [noRowsRendererHandler])
    
  • 所有配置对象、渲染数组用useMemo固化引用
    // 列配置固化
    const headersConfig = useMemo(() => ({
      // 你的列配置逻辑
    }), [/* 仅填写配置依赖的可变变量 */])
    
    // 表格列组件提前生成,避免每次渲染重绘
    const tableColumns = useMemo(() => {
      return Object.keys(headersConfig).map((key) => (
        <Column
          key={key}
          headerRenderer={headerRenderer}
          cellRenderer={cellRenderer}
          dataKey={key}
          width={headersConfig[key].width}
        />
      ))
    }, [headersConfig, headerRenderer, cellRenderer])
    
    // 行数据如果是加工生成的也需要固化
    const tableRowsData = useMemo(() => rawData.map(/* 数据加工逻辑 */), [rawData])
    
  • 表格单元格内的自定义子组件全部用React.memo包裹,仅当props变化时才更新
  • 调整overscanRowCount属性,默认值为10,可调低到3-5,减少滚动时预渲染的行数量,避免不必要的渲染开销

三、rowRenderer使用场景与实现示例

如果完成上述优化后滚动卡顿仍然存在,说明行内渲染逻辑过重,默认的Column嵌套层级太高,可以用rowRenderer自定义整行渲染,减少组件嵌套开销。

实现示例:

const rowRenderer = useCallback(({
  key,
  index,
  style,
  isScrolling,
}) => {
  // 滚动过程中可渲染简化占位符,进一步提升滚动流畅度
  if (isScrolling) {
    return <div key={key} style={style} className="row-placeholder">加载中</div>
  }

  const rowData = getRowRow(index)
  const rowClass = getRowClassName({index})

  return (
    <div key={key} style={style} className={rowClass}>
      {/* 直接渲染所有列,跳过Column组件的额外嵌套层级 */}
      {Object.keys(headersConfig).map(colKey => (
        <div 
          key={colKey}
          style={{width: headersConfig[colKey].width, display: 'inline-block'}}
        >
          {rowData[colKey]}
        </div>
      ))}
    </div>
  )
}, [getRowRow, getRowClassName, headersConfig])

// 传入Table组件后不需要再写Column子组件
<Table
  {/* 原有其他属性保持不变 */}
  rowRenderer={rowRenderer}
>
</Table>

内容的提问来源于stack exchange,提问作者dush

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.16 23:36:04