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

绘图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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 08:15:41