javascript 鼠标按下事件的useState不适用于画布

68bkxrlz  于 2022-11-27  发布在  Java
关注(0)|答案(2)|浏览(140)

我正在用React和Canvas制作一个绘图应用程序。但是,如果我将isMouseDown变量设置为useState而不是useRef,画布就不能绘图,我似乎找不到原因。下面是组件:

function App() {
  const [isMouseDown, setIsMouseDown] = useState(false);
  const isMouseDownRef = useRef(false);
  const canvasRef = useRef(null);
  const ctx = useRef(null);

  function triggerMouseDown() {
    setIsMouseDown(true);
    //isMouseDownRef.current = true;
  }

  function triggerMouseUp() {
    setIsMouseDown(false);
    //isMouseDownRef.current = false;
  }

  useEffect(() => {
    if(canvasRef.current) {
      ctx.current = canvasRef.current.getContext("2d");
      canvasRef.current.width = 720;
      canvasRef.current.height = 480;
      canvasRef.current.addEventListener("mousemove", (e) => {
        draw(
          e.clientX - canvasRef.current.getBoundingClientRect().left, 
          e.clientY - canvasRef.current.getBoundingClientRect().top
        )
      })

      canvasRef.current.addEventListener("mousedown", triggerMouseDown)

      window.addEventListener("mouseup", triggerMouseUp)
    }

    return () => {
      canvasRef.current.removeEventListener("mousedown", triggerMouseDown);
      window.removeEventListener("mouseup", triggerMouseUp)
    }
  }, [])

  function draw(x, y) {
    if(isMouseDown) {
      ctx.current.beginPath();
      ctx.current.fillStyle = "blue";
      ctx.current.arc(x, y, 20, 0, 2 * Math.PI);
      ctx.current.stroke();
    }
  }
  
  return (
    <div className="App">
      <canvas id="canvas1" ref={canvasRef}></canvas>
      <h1>{JSON.stringify(isMouseDown)}</h1>
    </div>
  );
}

我知道它不应该是一个useState,因为它会重新渲染太多,但我感兴趣的是为什么它不工作,特别是useState

pdtvr36n

pdtvr36n1#

我在代码中做了一些更改:
第一个

zkure5ic

zkure5ic2#

Y_T在this answer中的想法是正确的。不需要useEffect,但如果您 * 确实 * 使用useEffect,它应该在捕获组中使用isMouseDown,以便在适当的时间触发添加/删除移动侦听器。clearRect是可选的。类似于(单击并拖动可绘制):

useLayoutEffect(() => {
  if (!mouseDown) {
    return;
  }

  const canvas = canvasRef.current;
  const ctx = canvas.getContext("2d");
  const onMouseMove = e => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.arc(e.offsetX, e.offsetY, 20, 0, 2 * Math.PI);
    ctx.stroke();
  };
  canvas.addEventListener("mousemove", onMouseMove);

  return () => {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    canvas.removeEventListener("mousemove", onMouseMove);
  };
}, [mouseDown]);

但是,由于React提供了onMouseMove,我们可以直接使用它,而不是自己管理它:
第一次

相关问题