绘图App图片添加异常求助:点击图片延迟绘制至Canvas
绘图App Canvas图片绘制异常问题
我开发了一款绘图App,用户在画布上绘图后可选择推荐图片添加至Canvas中。目前存在异常:点击#img1无任何反应,继续绘图后再次点击#img2时,#img1才会被绘制到Canvas上。问题确定出在包含drawImage的DrawPicture函数中,相关代码如下:
图片与Canvas代码
<div> <img id={"img1"} src={Butterfly} onClick={ (event) => { takePicture(event); DrawPicture(); setPointsId(elements.length) } } style={{ cursor: "pointer" }} alt="Img1" /> <img id={"img2"} src={Butterfly2} onClick={ (event) => { takePicture(event); DrawPicture(); setPointsId(elements.length) } } style={{ cursor: "pointer" }} alt="Img2" /> <img id={"img3"} src={Butterfly3} onClick={ (event) => { takePicture(event); DrawPicture(); setPointsId(elements.length) } } style={{ cursor: "pointer" }} alt="img3" /> </div> <canvas onMouseDown={startDrawing} onMouseUp={endDrawing} onMouseMove={draw} onMouseLeave={endDrawing} ref={canvasRef} width={width} height={window.innerHeight} /> </div>
相关函数代码
function takePicture(event) { setImgSRC(event.target.src); } function DrawPicture() { var Se_image = new Image(); Se_image.onload = start; Se_image.src = ImgSRC; Se_image.onerror = function(){ alert(Se_image.src+"failed to load") } function start() { ctxRef.current.drawImage(Se_image, POx1, POY1, widthSize, heightSize); } }
注:POx1、POY1、widthSize、heightSize为已获取的变量。
问题原因
React的状态更新是异步的,调用setImgSRC后,ImgSRC不会立刻更新。当你在takePicture之后马上调用DrawPicture,此时DrawPicture读取的还是旧的ImgSRC值:
- 第一次点击
#img1,setImgSRC发起异步更新,DrawPicture用旧的ImgSRC(可能为空或其他旧值)加载图片,画布无变化; - 继续绘图触发组件重新渲染,
ImgSRC已更新为#img1的src;此时点击#img2,setImgSRC再次发起更新,DrawPicture读取到的是之前更新后的#img1的src,于是绘制出#img1。
解决方案
方式一:直接传递图片src给DrawPicture(推荐)
跳过React状态异步更新的等待,直接把点击事件中的图片src传给DrawPicture:
// 点击事件修改 (event) => { const imgSrc = event.target.src; DrawPicture(imgSrc); setPointsId(elements.length); } // DrawPicture函数修改 function DrawPicture(imgSrc) { const Se_image = new Image(); Se_image.onload = () => { ctxRef.current.drawImage(Se_image, POx1, POY1, widthSize, heightSize); }; Se_image.src = imgSrc; Se_image.onerror = () => alert(`${imgSrc} failed to load`); }
方式二:用useEffect监听状态变化
保留原点击事件,通过useEffect在ImgSRC状态更新完成后再触发绘制:
import { useEffect } from 'react'; // 组件内添加副作用监听 useEffect(() => { if (ImgSRC) { DrawPicture(); } }, [ImgSRC]); // 点击事件简化 (event) => { takePicture(event); setPointsId(elements.length); }
内容的提问来源于stack exchange,提问作者Masir
相关产品推荐
相关产品推荐

