Я реализовал защелкивающуюся кнопку, чтобы закрыть компонент меню на 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
) запускается перед обработчиками событий реакции ( выпуск github ).
Итак, мой вопрос: как обойти эту проблему?Можно ли вообще как-то запустить обработчик событий onBlur
, а затем запустить глобальный обработчик событий?
РЕДАКТИРОВАТЬ: я уже использую хак с setTimeout
внутри onClose
, чтобы временно заставить его работать, но я действительно хотел бы избежать этого и вместо этого найти лучшее решение.