React Hooks: useEffect для модального прослушивателя событий
У меня есть модальное диалоговое окно, которое я хочу закрыть, если пользователь нажимает за пределами модального. Я написал следующий код useEffect, но столкнулся со следующей проблемой:
Модальное диалоговое окно содержит несколько дочерних элементов (узлов реагирования), и эти дочерние элементы могут измениться (например, пользователь удаляет запись в списке). Эти взаимодействия запускают мой метод onClick, но поскольку элемент списка, по которому щелкнули мышью, был удален из модального режима, модальный режим закрывается, даже если щелчок был внутри модального элемента.
Я думал, что добавление [children] во втором параметре для useEffect очистит старый обработчик событий эффекта достаточно быстро, чтобы метод не запустился снова, но это не так.
Я обработал ту же проблему в компоненте класса с ignoreNextClick
- но должно быть более чистое решение, верно?
useEffect( () => {
const onClick = ( event ) => {
const menu = document.getElementById( 'singleton-modal' );
if ( !menu ) return;
// do not close menu if user clicked inside
const targetInMenu = menu.contains( event.target );
const targetIsMenu = menu === event.target;
if ( targetInMenu || targetIsMenu ) return;
onCloseModal();
};
window.addEventListener( 'click', onClick, false );
return () => window.removeEventListener( 'click', onClick, false );
}, [ children ] );
2 ответа
Я нашел решение, которое не требует какого-либо хранения старого реквизита.
Вызов useEffect выглядит следующим образом:
useEffect( () => {
const onClickOutside = () => onCloseModal();
window.addEventListener( 'click', onClickOutside, false );
return () => window.removeEventListener( 'click', onClickOutside );
}, [] );
Добавление следующего прослушивателя щелчков к модальному соединению не позволит вызывать прослушиватель окон, если пользователь щелкнул внутри модального окна.
<div
className={`modal ${ classes }`}
onClick={event => event.stopPropagation()}
role="presentation"
>
{children}
</div>`
Я также добавил презентацию роли, чтобы сделать модал более доступным и соответствующим арии.
Вы можете проверить родителя модального из event.target
, Если текущая цель находится в пределах модального, то return
,
Вы можете использовать ближайший, чтобы сделать это.
Смотрите следующее решение.
...
if (event.target.closest( '.singleton-modal' ) || event.target.classList.contains('singleton-modal')) {
return;
}
...