You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React渲染大量JSX元素数组性能优化及虚拟滚动实现方案咨询

性能优化方案

一、现有代码问题修复(立即可见性能提升)

  • 移除state中存储JSX元素的错误实践:state仅存储原始业务数据,不要存储已经渲染好的JSX节点,你的当前实现每次SSE更新都会全量替换JSX数组,触发所有卡片重渲染,性能损耗极高。
  • 优化SSE更新逻辑:不要在父层遍历所有卡片查找匹配项,将SSE推送的 payload 按imei为key存储为Map结构,每个DetailCard组件内部独立读取对应自身imei的最新数据,仅触发单卡片重渲染。
  • 完善DetailCard的memo比较逻辑:给memo传入第二个参数自定义浅比较规则,仅当卡片自身依赖的object1、object2属性发生变化时才触发重渲染,避免无效重绘。
  • 优化循环计算逻辑:缓存Object.keys(vehicleData)的结果,避免重复计算对象键值数组。
// 优化后的DetailCards示例
const DetailCards = memo(() => {
  const fetchDataContext = useContext(FetchDataContext)
  const { vehicleData, locationData, ssePayloadMap } = fetchDataContext // context里新增ssePayloadMap,key为imei,value为最新payload
  
  const vehicleKeys = useMemo(() => Object.keys(vehicleData), [vehicleData])
  const initialLocationData = useMemo(() => Object.keys(locationData).length ? locationData : null, [locationData])

  if (!initialLocationData) return null

  return vehicleKeys.map(imei => (
    <DetailCard 
      key={imei} 
      object1={vehicleData[imei]} 
      object2={ssePayloadMap.get(imei) || initialLocationData[imei]} 
    />
  ))
})

// DetailCard的memo自定义比较
const DetailCard = memo(({object1, object2}) => {
  // 内部业务逻辑
}, (prevProps, nextProps) => {
  // 只有object1和object2的核心展示字段变化才重渲染,可根据业务调整比较粒度
  return prevProps.object1.imei === nextProps.object1.imei 
    && prevProps.object2.timestamp === nextProps.object2.timestamp
})

二、虚拟化列表实现(大幅降低渲染量级,移动端提升明显)

虚拟化核心逻辑是仅渲染可视区域内的卡片,650个卡片实际可视区域最多同时展示10-20个,渲染量级直接降低90%以上,React17可以直接用react-window实现,适配你的PerfectScrollbar也很方便。

实现步骤

  1. 先确定你的卡片布局参数:每行展示的卡片数量columnCount、单个卡片的宽度cardWidth、高度cardHeight、容器的宽高。
  2. 替换原有平铺渲染的逻辑为Grid虚拟化组件,示例代码如下:
// 改造Contestants组件
import { FixedSizeGrid as Grid } from 'react-window'

const Contestants = memo(() => {
  const fetchDataContext = useContext(FetchDataContext)
  const { vehicleData, locationData, ssePayloadMap } = fetchDataContext
  const vehicleKeys = useMemo(() => Object.keys(vehicleData), [vehicleData])
  const columnCount = 3 // 每行3张卡片,可根据响应式规则调整
  const rowCount = Math.ceil(vehicleKeys.length / columnCount)
  const cardWidth = 280 // 按实际卡片宽度调整
  const cardHeight = 360 // 按实际卡片高度调整,高度不固定可以换用VariableSizeGrid

  const Cell = ({ columnIndex, rowIndex, style }) => {
    const index = rowIndex * columnCount + columnIndex
    if (index >= vehicleKeys.length) return null
    const imei = vehicleKeys[index]
    return (
      <div style={style}>
        <DetailCard 
          key={imei} 
          object1={vehicleData[imei]} 
          object2={ssePayloadMap.get(imei) || locationData[imei]} 
        />
      </div>
    )
  }

  return (
    <div className={`contestants-container animate__animated animate__fadeIn ${classes.mainContainer}`}>
      <div className={`mx-0 my-0 ${classes.cardsContainer}`}>
        <PerfectScrollbar>
          <Grid
            columnCount={columnCount}
            columnWidth={cardWidth}
            rowCount={rowCount}
            rowHeight={cardHeight}
            height={600} // 滚动容器的高度,按实际业务场景调整
            width="100%"
            className="d-flex flex-wrap align-items-center justify-content-evenly"
          >
            {Cell}
          </Grid>
        </PerfectScrollbar>
      </div>
    </div>    
  )
})

补充优化

  • 卡片内的图片添加懒加载属性,非可视区域的图片延迟加载
  • 图表组件单独用memo包裹,减少重渲染时的图表重绘开销
  • 如果卡片高度不固定,替换FixedSizeGrid为VariableSizeGrid,提前缓存每个卡片的高度即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 01:06:03