使用 React Hooks 在 mouseenter 和 mouseleave 上隐藏和显示模式

IT技术 reactjs react-hooks
2021-05-22 07:31:55

我尝试添加条件mouseentermouseleave但是模态不起作用但是当我尝试创建button onClick={() => {openModal();}}模态时会出现。你能告诉我我的代码有什么问题以及哪一部分。

const openModal = event => {
    if (event) event.preventDefault();
    setShowModal(true);
  };

  const closeModal = event => {
    if (event) event.preventDefault();
    setShowModal(false);
  };

  function useHover() {
    const ref = useRef();
    const [hovered, setHovered] = useState(false);
    const enter = () => setHovered(true);
    const leave = () => setHovered(false);

    useEffect(() => {
      if (ref.current.addEventListener('mouseenter', enter)) {
        openModal();
      } else if (ref.current.addEventListener('mouseleave', leave)) {
        closeModal();
      }
      return () => {
        if (ref.current.addEventListener('mouseenter', enter)) {
          openModal();
        } else if (ref.current.addEventListener('mouseleave', leave)) {
          closeModal();
        }
      };
    }, [ref]);

    return [ref, hovered];
  }

  const [ref, hovered] = useHover();



<div className="hover-me" ref={ref}>hover me</div>

  {hovered && (
    <Modal active={showModal} closeModal={closeModal} className="dropzone-modal">
      <div>content here</div>
    </Modal>
  )}
2个回答

Drew Reese 的回答为基础,您可以将节点引用缓存在 useEffect 闭包本身内,它简化了一些事情。您可以在此 stackoverflow 线程中阅读有关闭包的更多信息

const useHover = () => {
  const ref = useRef();
  const [hovered, setHovered] = useState(false);
  const enter = () => setHovered(true);
  const leave = () => setHovered(false);

  useEffect(() => {
    const el = ref.current; // cache external ref value for cleanup use
    if (el) {
      el.addEventListener("mouseenter", enter);
      el.addEventListener("mouseleave", leave);

      return () => {
        el.removeEventLisener("mouseenter", enter);
        el.removeEventLisener("mouseleave", leave);
      };
    }
  }, []);

  return [ref, hovered];
};

我几乎放弃并通过了这个,但这是一个有趣的问题。

问题:

  • 第一个主要问题是useEffect钩子的useHover钩子,当引用的当前组件挂载和卸载时,它需要同时添加/删除两个事件侦听器。关键部分是钩子需要缓存效果钩子中的当前引用,以便清理功能正确运行。

  • 第二个问题是您没有删除返回的效果挂钩清理函数中的侦听器。

  • 第三个问题是EventTarget.addEventListener()回报undefined,这是一个falsey值,从而钩子永远不会调用modalOpen modalClose

  • 最后一个问题是模式打开/关闭状态/回调与useHover钩子的实现耦合这很好,但是在这种级别的耦合下,您还不如将钩子逻辑直接放在父组件中,完全违背了将其分解为可重用钩子的意义!

解决方案

这是我能够开始工作的内容:

const useHover = () => {
  const ref = useRef();
  const _ref = useRef();
  const [hovered, setHovered] = useState(false);
  const enter = () => setHovered(true);
  const leave = () => setHovered(false);

  useEffect(() => {
    if (ref.current) {
      _ref.current = ref.current; // cache external ref value for cleanup use
      ref.current.addEventListener("mouseenter", enter);
      ref.current.addEventListener("mouseleave", leave);
    }

    return () => {
      if (_ref.current) {
        _ref.current.removeEventLisener("mouseenter", enter);
        _ref.current.removeEventLisener("mouseleave", leave);
      }
    };
  }, []);

  return [ref, hovered];
};

编辑 awesome-bardeen-cnqjs

注意:正如我所怀疑的那样,将它与模态一起使用似乎存在交互问题,但也许您的模态效果更好。