简体   繁体   中英

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

I'm coding a super basic canvas-based image viewer. I'm trying to implement image panning. I want to be able to hold my mouse button down and move the mouse to pan the image around. I'm using the mouse up and down events to enter and leave a "panning mode". My mouse move handler never seems to see that the panning boolean changes from false to true, though.

I've tried writing my functions as arrow functions instead, thinking maybe it was something to do with the fact that these are DOM handlers (issues with this or something), but that didn't seem to make any difference.

I have a heads-up display that shows the panning state and it updates accordingly, but my console logs within the mouse move handler always show the variable as false.

How can I get this panning boolean value to update as you'd expect within my mouse move handler?

Here is my trimmed down code, which is testable in my codepen link further down...

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"));

Here is a testable code sample. You have to bring up the console to see the console logs of the variable never changing to true as you move your mouse and hold down the mouse button. You see though that the text above the canvas changes to show that it's changing from false to true...

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

you have at least two solutions here:

Solution 1:

declare listener on canvas:

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

and use native event in the handleMouseMove :

const {x, y} = ev.nativeEvent;

Solution 2:

instruct useEffect to update value of isDragging :

React.useEffect(componentMountEffect, [isDragging]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM