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

React中实现Canvas图片动画:避免每次间隔重复加载图片

React Canvas图片移动动画:避免重复加载卡顿的解决方案

问题现象

在React组件的Canvas中通过setInterval实现图片移动动画时,遇到以下问题:

  • 在绘制函数内部定义Image对象,动画可正常运行,但每次定时器触发都会重新加载图片,导致动画卡顿
  • 将Image对象定义在绘制函数外部,要么图片无法显示,要么抛出错误:
    Uncaught DOMException: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.
    

解决方法

核心思路:利用useRef持久化Image对象,在组件初始化时加载一次图片;通过状态变量监听图片加载状态,确保绘制操作仅在图片就绪后执行;同时通过ES模块导入图片资源,避免路径解析问题。

完整实现代码

import React, { useRef, useEffect, useState } from "react";
import image1 from "./images/image.png";

function MyCanvasComponent() {
  const canvasRef = useRef(null);
  const imageRef = useRef(null);
  const [imageLoaded, setImageLoaded] = useState(false);

  useEffect(() => {
    imageRef.current = new Image();
    imageRef.current.onload = () => setImageLoaded(true);
    imageRef.current.src = image1;
  }, []);

  function draw(image, x) {
    if (canvasRef.current) {
      const canvas = canvasRef.current;
      const context = canvas.getContext("2d");
      context.clearRect(0, 0, canvas.width, canvas.height);
      context.drawImage(image, x, 0, image.width, image.height);
    }
  }

  let counter = 1;
  setInterval(() => {
    if (imageLoaded) {
      draw(imageRef.current, counter % 2 === 0 ? 200 : 100);
      counter++;
    }
  }, 1000);
  
  return (
    <div>
      <canvas ref={canvasRef} width={300} height={200} />
    </div>
  );
}

function App() {
  return (
    <div>
      <h1>My Canvas App</h1>
      <MyCanvasComponent />
    </div>
  );
}

export default App;

原尝试的两种写法

  1. 可运行但重复加载图片的写法
function draw() {
  const canvas = canvasRef.current;
  const context = canvasRef.current.getContext("2d");
  const image = new Image();
  image.onload = () => {
    context.drawImage(image, x, y, laius, korgus);
  };
  image.src = imageSource;
}
  1. 报错或无显示的写法
function draw() {
  const canvas = canvasRef.current;
  const context = canvasRef.current.getContext("2d");
  context.drawImage(image, x, y, laius, korgus);
}
const image = new Image();
image.onload = () => {
  draw();
};
image.src = imageSource;

内容的提问来源于stack exchange,提问作者Priit Kenkmann

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 11:35:09