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

React中useEffect执行两次致Canvas重复绘制问题求助

React useEffect执行两次导致Canvas文字重复绘制问题解决

问题描述

我正在开发一个基于HTML Canvas的白板应用,在Canvas上绘制文字时发现内容被重复绘制了两次。调试后发现挂载时的useEffect钩子执行了两次,但我期望它仅在组件挂载时执行一次。相关代码如下:

import React, { useEffect, useRef } from "react";

const WhiteBoard = () => {
  const canvasid = useRef();

  useEffect(() => {
    const canvas = canvasid.current;
    const ctx = canvas.getContext("2d");

    ctx.font = "30px Impact";
    ctx.rotate(0.1);
    ctx.fillText("Awesome!", 50, 100);

    // Draw line under text
    var text = ctx.measureText("Awesome!");
    ctx.strokeStyle = "rgba(0,0,0,0.5)";
    ctx.beginPath();
    ctx.lineTo(50, 102);
    ctx.lineTo(50 + text.width, 102);
    ctx.stroke();
  }, []);

  return (
    <>
      <div>WhiteBoard</div>
      <canvas ref={canvasid} style={{ border: "1px solid red" }}></canvas>
    </>
  );
};

export default WhiteBoard;

原因分析

这是React 18在开发环境下的Strict Mode默认行为。Strict Mode会刻意重复执行不带依赖项的useEffect等生命周期钩子,目的是帮你提前检测潜在的副作用问题(比如未正确清理的资源、重复创建的订阅),生产环境下不会出现这个重复执行的情况。

解决方法

1. 开发环境临时禁用Strict Mode(可选)

如果只是想在开发阶段避免这个现象,可以在根组件中移除<StrictMode>包裹。比如index.js中:

// 移除<StrictMode>标签
ReactDOM.createRoot(document.getElementById('root')).render(
  <App />
);

但不推荐长期这么做,因为Strict Mode能帮你发现很多隐藏的代码问题。

2. 给Canvas添加清理逻辑(推荐)

更规范的做法是在useEffect执行绘制前先清空Canvas,确保每次绘制都是在干净的画布上进行。同时可以在清理函数中做卸载时的清理:

useEffect(() => {
  const canvas = canvasid.current;
  const ctx = canvas.getContext("2d");

  // 绘制前清空整个Canvas
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  ctx.font = "30px Impact";
  ctx.rotate(0.1);
  ctx.fillText("Awesome!", 50, 100);

  // 绘制文字下划线
  const text = ctx.measureText("Awesome!");
  ctx.strokeStyle = "rgba(0,0,0,0.5)";
  ctx.beginPath();
  ctx.lineTo(50, 102);
  ctx.lineTo(50 + text.width, 102);
  ctx.stroke();

  // 组件卸载时清空Canvas(可选)
  return () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
  };
}, []);

另外,建议给Canvas设置固定的width和height属性,避免绘图缓冲区尺寸与显示尺寸不一致的问题:

<canvas ref={canvasid} width={800} height={600} style={{ border: "1px solid red" }}></canvas>

内容的提问来源于stack exchange,提问作者Yash Narang

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 20:25:22