使用事件侦听器进行反应的自定义钩子在更新状态时不起作用

时间:2019-11-18 15:55:00

标签: reactjs react-hooks

我有一个自定义钩子,用于处理组件外部的点击:

const useOutsideClick = (ref, callback) => {
  const handleClick = e => {

    if (ref.current && !ref.current.contains(e.target)) {
      callback();
    }
  };

  useEffect(() => {
    document.addEventListener("click", handleClick);

    return () => {
      document.removeEventListener("click", handleClick);
    };
  });
};

我在这样的组件中使用了这个钩子:

const MyComponent = () => {
  const container = useRef();
  const [isOpen, setIsOpen] = useState(false);

  useOutsideClick(container, () => {
    console.log("clicked outside");
  });
  return (
    <>
      <span>another element</span>

      <button onClick={() => setIsOpen(false)}>click</button>
      <div ref={container}></div>
    </>
  );
};

问题是当我单击跨度时,一切正常。但是,当我单击按钮并更新状态时,它没有进入useOutsideClick回调函数。我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

这里的问题是Finished没有依赖项数组,因此在每个渲染器上都将调用它。另外,最好将useEffect的定义保留在钩子中,因为它将仅在第一个渲染中使用。否则,将在每个渲染器上进行定义。

handleClick

答案 1 :(得分:0)

我发现useOutsideClick挂钩的最佳解决方案是:

function useOutsideClick(ref, handler) {
  useEffect(
    () => {
      const listener = event => {
        if (!ref.current || ref.current.contains(event.target)) {
          return;
        }

        handler(event);
      };

      document.addEventListener("mousedown", listener);
      document.addEventListener("touchstart", listener);

      return () => {
        document.removeEventListener("mousedown", listener);
        document.removeEventListener("touchstart", listener);
      };
    },

    [ref, handler]
  );
}