如何获取 canvas onmousemove 处理程序以查看最新的 React 状态挂钩值?

How to get canvas onmousemove handler to see latest React state hook value?

我正在编写一个基于 canvas 的超级基本图像查看器。我正在尝试实现图像平移。我希望能够按住鼠标按钮并移动鼠标来平移图像。我正在使用鼠标上下事件进入和离开“平移模式”。不过,我的鼠标移动处理程序似乎从未看到平移布尔值从 false 变为 true。

我试过将我的函数写成箭头函数,我想这可能与这些是 DOM 处理程序(this 或其他问题)这一事实有关,但是似乎没有任何区别。

我有一个显示平移状态的平视显示器,它会相应地更新,但我在鼠标移动处理程序中的控制台日志始终将变量显示为 false。

我怎样才能让这个平移布尔值按照您在我的鼠标移动处理程序中所期望的那样更新?

这是我精简的代码,可以在我的 codepen link 中进一步测试...

import * as React from "https://cdn.skypack.dev/react@17.0.1";
import * as ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";

type PropsType = {
  url: string;
};

function ImageViewer(props: PropsType) {
  const imgRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  
  const [isDragging, setIsDragging] = React.useState(false);
  
  function imageUrlChangeEffect() {
    imgRef.current.src = props.url;
  }
  
  function componentMountEffect() {
    imgRef.current.onload = handleImageLoad;
    canvasRef.current.onmouseup = handleMouseUp;
    canvasRef.current.onmousedown = handleMouseDown;
    canvasRef.current.onmousemove = handleMouseMove;
  }

  function handleMouseUp() {
    setIsDragging(false);
  }
  
  function handleMouseDown() {
    setIsDragging(true);
  }
  
  function handleMouseMove(ev) {
    const {x, y} = ev;
    console.log({x, y, isDragging});
  }
  
  function handleImageLoad() {
    clearCanvas();
    drawImage();
  }
  
  function clearCanvas() {
    const context = canvasRef.current.getContext("2d");
    context.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height);
  }
    
  function drawImage() {
    const context = canvasRef.current.getContext("2d");
    context.drawImage(imgRef.current, 0, 0, imgRef.current.width, imgRef.current.height);
  }

  React.useEffect(componentMountEffect, []);
  React.useEffect(imageUrlChangeEffect, [props.url]);

  return (
    <div className="image-viewer">
      <p>is dragging: {isDragging.toString()}</p>
      <canvas ref={canvasRef} width="600" height="200"></canvas>
      <img ref={imgRef} />
    </div>
  );
}

ReactDOM.render(
  <ImageViewer url="https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png" />,
  document.getElementById("container"));

这是一个可测试的代码示例。当您移动鼠标并按住鼠标按钮时,您必须调出控制台才能看到变量的控制台日志永远不会更改为 true。您看到 canvas 上方的文本发生变化,表明它正在从 false 变为 true ...

https://codepen.io/betawarz/pen/poRQdpa

您至少有两个解决方案:

解决方案 1:

在 canvas 上声明侦听器:

<canvas ref={canvasRef} width="600" height="200" onMouseMove={handleMouseMove}></canvas>

并在 handleMouseMove 中使用本机事件:

const {x, y} = ev.nativeEvent;

解决方案 2:

指示useEffect更新isDragging的值:

React.useEffect(componentMountEffect, [isDragging]);