Search code examples
javascriptreactjsmouselistener

React can't trigger window.onmouseup


I have a slider component, which should stop moving after mouse is up. I have went through the forum and my code is very similar to the one here

const Slider = ({ mainColour }) => {
  const [cursorPos, setCursorPos] = React.useState(0);
  const [isSliding, setSliding] = React.useState(false);
  const ref = React.useRef();

  const drag = e => {
    console.log("dragging");
    setCursorPos(e.pageY);
  };

  const startDrag = e => {
    setSliding(true);
    window.addEventListener("mousemove", drag);
    window.addEventListener("mouseup", function() {
      ref.current.onmousedown = null;
      ref.current.onmouseup = null;
      ref.current.onmousemove = null;
      setSliding(false);
      window.onmouseup = null;
    });
  };

  return (
    <div
      className={`cursor ${isSliding ? "active" : ""}`}
      ref={ref}
      style={{
        top: `${cursorPos}px`,
        backgroundColor: `${mainColour}`
      }}
      onMouseDown={event => startDrag(event)}
    ></div>
  );
};

export default Slider;

However, when startDrag triggers, the window.onmouseup listener doesn't seem to be working and does not stop the slider. Will be appreciated for any insights why it doesn't work.


Solution

  • https://codesandbox.io/s/lucid-sunset-8e78r

    React can trigger mouseup, you just need to use window.removeEventListener for drag() when you mouseup. That's why you see dragging in the console after mouseup, you just forgot to unsubscribe from the event :)

    window.onmouseup = null; is not the same as window.removeEventListener("mousemove").

    const Slider = ({ mainColour }) => {
      const [cursorPos, setCursorPos] = React.useState(0);
      const [isSliding, setSliding] = React.useState(false);
      const ref = React.useRef();
    
      const drag = e => {
        console.log("dragging");
        setCursorPos(e.pageY);
      };
    
      useEffect(() => {
        if (isSliding) {
          window.addEventListener("mousemove", drag);
        }
      }, [isSliding]);
    
      useEffect(() => {
        window.addEventListener("mouseup", function() {
          window.removeEventListener("mousemove", drag);
          setSliding(false);
        });
      });
    
      const startDrag = () => setSliding(true);
    
      return (
        <div
          className={`cursor ${isSliding ? "active" : ""}`}
          ref={ref}
          style={{
            top: `${cursorPos}px`,
            backgroundColor: `${mainColour}`
          }}
          onMouseDown={event => startDrag(event)}
        />
      );
    };