单击外部的全局事件处理程序可防止触发反应事件

时间:2019-03-25 23:29:38

标签: reactjs dom-events react-dom

我已经实现了点击外钩以关闭文档mousedown上的菜单组件:

const useClickOutside = onClickOutside => {
  const ref = useRef(null);
  useEffect(
    () => {
      const handleClickOutside = e => {
        if (ref.current && !ref.current.contains(e.target)) {
          onClickOutside(e);
        }
      };
      document.addEventListener("mousedown", handleClickOutside);
      return () => {
        document.removeEventListener("mousedown", handleClickOutside);
      };
    },
    [onClickOutside, ref]
  );
  return ref;
};

菜单的输入附加了onBlur事件处理程序:

const Input = ({ onValueEnter }) => {
  const [value, setValue] = useState("");
  const handleValueChange = e => setValue(e.target.value);
  const handleBlur = () => onValueEnter(value);

  return (
   <input onBlur={handleBlur} value={value} onChange={handleValueChange} />
  );
};

const Menu = ({ onClose }) => {
  const ref = useClickOutside(onClose);
  return (
    <div ref={ref} className="menu">
      <h1>Enter value</h1>
      <Input onValueEnter={handleValueEnter} />
    </div>
  );
};

问题是,如果我将焦点放在输入并在菜单外单击,则输入上的onBlur事件永远不会触发。 Codesandbox示例在这里。

显然,由于react通过将事件附加到顶层而不是实际的dom节点来实现了自己的事件委托系统,因此全局事件处理程序(如在document.addEventListener中注册的事件处理程序)在react事件之前运行处理程序(github issue)。

所以我的问题是,如何解决这个问题?甚至有可能使onBlur事件处理程序首先运行,然后再运行全局事件处理程序吗?

编辑:我已经在setTimeout内部使用onClose进行黑客攻击,以使其暂时起作用,但我真的想避免使用它,而是找到一种更好的解决方案。

1 个答案:

答案 0 :(得分:0)

我一起砍了一些东西使其工作。它围绕着在关闭时使用forwardRef和imperativeHandle从child访问值的方法。我不知道这是否能解决您的问题。

https://codesandbox.io/embed/zw7jjopqq4