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;
    }

...
Другие вопросы по тегам