Глобальный обработчик событий при щелчке снаружи предотвращает срабатывание событий реагирования - PullRequest
0 голосов
/ 26 марта 2019

Я реализовал защелкивающуюся кнопку, чтобы закрыть компонент меню на 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, чтобы временно заставить его работать, но я действительно хотел бы избежать этого и вместо этого найти лучшее решение.

1 Ответ

0 голосов
/ 26 марта 2019

Я взломал что-то вместе, чтобы это заработало.Он вращается вокруг использования forwardRef и imperativeHandle для доступа к значению child при закрытии.Я не знаю, решит ли это ваш вопрос все же.

https://codesandbox.io/embed/zw7jjopqq4

...