React使用Array.map渲染游戏走棋列表性能低下如何结合ListItemText现象优化
性能卡顿原因
- 重复调用
history()方法:代码中2个列表各自触发一次全量props.chess.history().map遍历,同时每个ListItemText内部又单独调用props.chess.history()[index]取值,相当于每次组件更新都多次执行history()生成数组,走棋数量越多,重复计算的开销越大。 - 缺少列表渲染唯一key:React的列表项必须绑定唯一key属性,否则每次组件更新都会全量重渲染所有列表节点,而非仅更新选中状态变化的节点,走棋数量大时重渲染开销会成倍增长。
ListItemText额外开销:Material UI的ListItemText内部默认封装了排版适配、样式合并、文本截断等额外逻辑,你注释掉该组件后跳过了每个列表项的这部分计算,所以速度大幅提升,再加上你自定义了行高、类名,又额外增加了样式计算的开销。- 无用遍历开销:两个列表的map逻辑中都有一半的判断分支返回null,等于遍历了2倍总走棋长度的数组,做了大量无意义的判断逻辑。
优化方案
- 缓存history计算结果:组件渲染前先把走棋数组缓存下来,所有场景复用同一个数组,避免重复调用
history():
const history = props.chess.history()
- 提前拆分奇偶走棋数组:不要在map内做奇偶判断,提前过滤出白方、黑方的走棋数组,再分别渲染,避免无用遍历:
const whiteMoves = history.filter((_, index) => index % 2 === 0) const blackMoves = history.filter((_, index) => index % 2 !== 0)
- 补充列表项key:给所有
ListItem绑定key属性,走棋顺序固定的场景直接用index作为key即可,降低React的重渲染开销。 - 替换
ListItemText为原生元素:不需要ListItemText内置功能的场景,直接用原生标签渲染走棋文本,省掉MUI组件的额外计算:
<span style={{ lineHeight: 0, margin: 0 }} className={props.classes.listItemText} > {each} </span>
- 组件更新拦截:用
React.memo包裹MoveList组件,仅当chess、selectedIndex、classes等依赖变化时才触发组件重渲染,避免父组件无关更新导致的多余渲染。 - 大数量场景用虚拟滚动:如果走棋数量经常超过100条,接入虚拟滚动方案,仅渲染可视区域内的列表项,不管总走棋量多大,渲染节点数都固定在几十条,性能会有量级提升。
内容的提问来源于stack exchange,提问作者Jon
相关产品推荐
相关产品推荐

