在React中缓存大量重复KonvaJS图形的正确方法
KonvaJS批量图形缓存优化方案
你当前代码的核心问题是同一个ref被绑定到了所有Rect组件上,React的ref在循环中只会指向最后一个渲染的元素,所以只有最后一个矩形被执行了cache(),前面的999个都没生效,这就是缓存没起作用的原因。
下面是两种可行的优化方案:
方案一:每个图形实例独立缓存
创建一个封装好的缓存矩形组件,每个实例内部自行完成缓存操作:
import { Rect } from 'react-konva'; import { useRef, useEffect } from 'react'; const CachedAircraftRect = ({ x, y }) => { const rectRef = useRef(null); useEffect(() => { if (rectRef.current) { rectRef.current.cache(); } }, []); return ( <Rect ref={rectRef} width={120} height={40} fill={'red'} perfectDrawEnabled={false} hitStrokeWidth={0} shadowForStrokeEnabled={false} x={x} y={y} /> ); }; export default function AircraftLayer() { const { aircrafts } = useAircraft(); return ( <Layer> {aircrafts.map((aircraft, index) => ( <CachedAircraftRect key={index} x={aircraft.positionX} y={aircraft.positionY} /> ))} </Layer> ); }
方案二:模板克隆(更高效)
因为所有图形样式完全一致,只需要缓存一个模板实例,然后通过克隆模板来生成所有图形,这种方式只需要执行一次缓存操作,性能最优:
import { Layer, Node } from 'react-konva'; import { useState, useEffect } from 'react'; import { useAircraft } from './your-path'; export default function AircraftLayer() { const { aircrafts } = useAircraft(); const [cachedTemplate, setCachedTemplate] = useState(null); useEffect(() => { // 创建模板并缓存 const template = new window.Konva.Rect({ width: 120, height: 40, fill: 'red', perfectDrawEnabled: false, hitStrokeWidth: 0, shadowForStrokeEnabled: false, }); template.cache(); setCachedTemplate(template); }, []); return ( <Layer> {cachedTemplate && aircrafts.map((aircraft, index) => { // 克隆模板并修改位置 const clonedRect = cachedTemplate.clone(); clonedRect.x(aircraft.positionX); clonedRect.y(aircraft.positionY); return <Node key={index} node={clonedRect} />; })} </Layer> ); }
额外性能优化建议
- 必须给循环渲染的元素添加唯一
key,避免React不必要的重渲染 - 可以开启Layer的
imageSmoothingEnabled={false}(如果不需要图形平滑效果),进一步提升渲染速度 - 如果需要频繁更新位置,使用
layer.batchDraw()批量处理重绘,减少渲染次数
内容的提问来源于stack exchange,提问作者Jordan
相关产品推荐
相关产品推荐

