0

Here is the situation,

const MyComp = () => {
    const timelineOverlayRef = useRef(null);
    const [position, setPosition] = useState({ x: 0, y: 0 });

    const mouseDownHandler = e => {
        setPosition({ x: 0, y: 100});
    };

    const mouseMoveHandler = e => {
        console.log(position);
    }

    const init = () => {
        timelineOverlayRef.current.addEventListener('mousemove', mouseMoveHandler);

        timelineOverlayRef.current.addEventListener('mousedown', mouseDownHandler);

    }

    useEffect(init, []);

    return <div ref={timelineOverlayRef}>My Div where I want to capture mouse down and mouse move events</div>;
}

When I click on my div and start moving the mouse I don't see the updated position where y equals 100. instead I have the initial state value with y = 0. Any idea on why this might happen and how to overcome this will be really appreciated.

Md Sabbir Alam
  • 4,937
  • 3
  • 15
  • 30

1 Answers1

1

Use onMouseMove and onMouseDown events on div.

const MyComp = () => {
  const timelineOverlayRef = useRef(null);
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const mouseDownHandler = e => {
    setPosition({ x: 0, y: 100 });
  };

  const mouseMoveHandler = e => {
    console.log(position);
  };

  return (
    <div
      ref={timelineOverlayRef}
      onMouseMove={mouseMoveHandler}
      onMouseDown={mouseDownHandler}
    >
      My Div where I want to capture mouse down and mouse move events
    </div>
  );
};  

Your code is not working because new instances of event handler functions are being created each time component re-renders and event listener has old reference of the function which was created after component was mounted.

Add the event handler functions as dependencies of useEffect and remove the events in clean-up function.

The following code should work fine.

const MyComp = () => {
  const timelineOverlayRef = useRef(null);
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const mouseDownHandler = e => {
    console.log("clicked...");
    setPosition({ x: 0, y: 100 });
  };

  const mouseMoveHandler = e => {
    console.log(position);
  };

  const init = () => {
    timelineOverlayRef.current.addEventListener("mousemove", mouseMoveHandler);
    timelineOverlayRef.current.addEventListener("mousedown", mouseDownHandler);

    return () => {
      timelineOverlayRef.current.removeEventListener(
        "mousemove",
        mouseMoveHandler
      );
      timelineOverlayRef.current.removeEventListener(
        "mousedown",
        mouseDownHandler
      );
    };
  };

  useEffect(init, [mouseDownHandler, mouseMoveHandler]);

  return (
    <div ref={timelineOverlayRef}>
      My Div where I want to capture mouse down and mouse move events
    </div>
  );
};  

To make above code simpler, you can use this custom hook: https://usehooks.com/useEventListener/

Murli Prajapati
  • 8,833
  • 5
  • 38
  • 55