React 无法触发 window.onmouseup

React can't trigger window.onmouseup

我有一个滑块组件,它应该在鼠标抬起后停止移动。我浏览了论坛,我的代码与

非常相似
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;

但是,当 startDrag 触发时,window.onmouseup 侦听器似乎没有工作并且不会停止滑块。对于为什么它不起作用的任何见解,我们将不胜感激。

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

React 可以触发mouseup,你只需要在mouseup 时为drag() 使用window.removeEventListener。这就是为什么您在 mouseup 之后在控制台中看到 dragging 的原因,您只是忘记取消订阅该事件:)

window.onmouseup = null;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)}
    />
  );
};

我同意 artanik 的评论,但有非常细微的变化。我宁愿只在 isSliding 更改值时设置和取消设置它,而不是在没有任何依赖项的情况下使用 useEffect,并不断地从 window 对象中添加和删除事件侦听器。此外,似乎 ref 没有在任何地方使用,所以我假设你可以只为 ref.

中的元素设置它而不是使用 window 对象

用空数组触发一次 useEffect 的目的是为了不 运行 它每次渲染。想象一个组件会发生大量状态更改和数据通过它,不需要在每次渲染时一次性添加和删除一堆事件侦听器。

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

  ///only do this once, when the component mounts
  useEffect(() => {
    window.addEventListener("mousedown", startDrag);
    window.addEventListener("mouseup", endDrag);
  },[]);

  //and setting and unseting the event as needed
  useEffect(() => {
    if (isSliding) {
      window.onmousemove = handleDrag;
    }
    else{
      window.onmousemove = null;
    }

  }, [isSliding]);

  const startDrag = () => setSliding(true);
  const endDrag = () => setSliding(false);

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

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