我已经实现了click-outside挂钩来关闭文档上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
的hack来暂时使其工作但我真的想避免它并找到更好的解决方案。
我把一些东西混在一起让它起作用。它围绕使用forwardRef和imperativeHandle来关闭时从子访问值。我不知道这是否能解决你的问题。