reactjs重新渲染时画布闪烁

Posted

技术标签:

【中文标题】reactjs重新渲染时画布闪烁【英文标题】:Canvas flickering when reactjs re-renders 【发布时间】:2015-06-05 04:46:30 【问题描述】:

我在同时使用 React JS 和画布时遇到了问题。

一切似乎都很顺利,但是当我的应用程序画布的其他部分发生变化而调用渲染方法时会闪烁。似乎 react 正在将其重新附加到 DOM 中(可能是因为我在其上播放动画,并且每次绘制的帧都不同)。

这是我的渲染方法:

render: function() 
 var canvasStyle = 
   width: this.props.width
 ;

 return (
   <canvas id="interactiveCanvas" style=canvasStyle/>
 );

作为一种临时解决方案,我手动添加我的画布标签,而不使用 reactjs:

render: function() 
var canvasStyle = 
  width: this.props.width
;
return (
  <div id="interactivediv3D">

  </div>
);

然后:

componentDidMount: function() 
var canvasStyle = 
  width: this.props.width
;

var el = document.getElementById('interactivediv3D');

el.innerhtml = el.innerHTML + 
    '<canvas id="interactive3D" style='+canvasStyle+'/>';
 ,

而且它工作正常。但我认为这不是一种干净的方式,最好使用reactjs渲染这个canvas标签。

知道如何解决这个问题吗?或者至少避免在仅绘制框架更改时reactjs重新渲染此画布。

【问题讨论】:

还有其他原因导致您描述的重新渲染。我创建了这个简单的 jsFiddle (jsfiddle.net/wiredprairie/amq1t7jc),它创建了一个画布,然后每 16 毫秒覆盖一次画布。由于未重新创建画布,它不会闪烁。 【参考方案1】:

我遇到了同样的问题。我使用了react-konva 库,我的组件结构看起来像这样:画布有一个背景图像&lt;SelectedImage /&gt;,每次任何状态属性更改时都会闪烁。初始代码

import React,  useState  from "react";
import  Stage, Layer, Image  from "react-konva";
import useImage from "use-image";

function SomeComponent() 
    const [imgWidth, setImgWidth] = useState(0);
    const [imgHeight, setImgHeight] = useState(0);
    //...and other state properties

    const SelectedImage = () => 
        const [image] = useImage(imgSRC);
        if (imgWidth && imgHeight) 
            return <Image image=image width=imgWidth height=imgHeight />;
        
        return null;
    ;

    return (
        <div>
            <Stage width=imgWidth height=imgHeight>
                <Layer>
                    <SelectedImage />
                    /* some other canvas components*/
                </Layer>
            </Stage>
        </div>
    );


export default SomeComponent;

解决方案 问题在于 SomeComponent 的错误结构,其中一个组件在另一个组件中初始化。在我的例子中,它是SomeComponent 内部的&lt;SelectedImage /&gt;。我把它取出到一个单独的文件中,闪烁消失了! 这是一个正确的结构

SelectedImage.js

import React from "react";
import  Image  from "react-konva";
import useImage from "use-image";

function SelectedImage( width, height, imgSRC ) 
    const [image] = useImage(imgSRC);
    if (width && height) 
        return <Image image=image width=width height=height />;
    
    return null;


export default SelectedImage;

SomeComponent.js

import React,  useState  from "react";
import  Stage, Layer, Image  from "react-konva";
import SelectedImage from "./SelectedImage";

function SomeComponent() 
    const [imgWidth, setImgWidth] = useState(0);
    const [imgHeight, setImgHeight] = useState(0);
    //...and other state properties

    return (
        <div>
            <Stage width=imgWidth height=imgHeight>
                <Layer>
                    <SelectedImage width=imgWidth height=imgHeight imgSRC=imgSRC />
                    /* some other canvas components*/
                </Layer>
            </Stage>
        </div>
    );


export default SomeComponent;

【讨论】:

【参考方案2】:

我花了一些时间观察您的建议,发现这种闪烁是由于每次调用 onComponentDidUpdate 时我都在访问 canvas DOM 元素并更改 canvas.width 和 canvas.height 造成的。

我需要手动更改此属性,因为在渲染时我还不知道 canvas.width。我用“100%”填充样式宽度,渲染后我查看“canvas.clientWidth”以提取像素值。

正如这里所解释的:https://facebook.github.io/react/tips/dom-event-listeners.html 我附加了 resize 事件,现在我只从我的 resizeHandler 更改画布属性。

【讨论】:

【参考方案3】:

重新渲染整个树不应导致画布闪烁。但是如果您认为重新渲染导致了这个问题,您可以使用shouldComponentUpdate 生命周期函数并在您不想更新时返回 false。

https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate

例如:

shouldComponentUpdate: function(nextProps, nextState) 
    return false;

任何定义了上述函数的组件都不会多次运行render(在组件安装时)。

但是,我无法复制您抱怨的闪烁问题。您的整个树渲染是否过于频繁?在这种情况下,上述内容将修复您的画布,但您应该查看重新渲染整个树的次数和频率,并修复那里的任何问题。

【讨论】:

以上是关于reactjs重新渲染时画布闪烁的主要内容,如果未能解决你的问题,请参考以下文章

如何在状态更改(父)reactjs时重新渲染子组件

重新渲染 Reactjs 后,父组件立即失去状态

reactjs:动作后redux不会重新渲染

重新渲染 Reactjs 数组组件

ReactJS:即使在重新渲染组件后复​​选框状态仍然存在

如何通过一劳永逸地重新渲染来修复图像闪烁?