简体   繁体   English

React Hooks:useEffect用于模态事件监听器

[英]React Hooks: useEffect for modal event listener

I have a modal dialog that I want to close if the user clicks outside of the modal. 我有一个模态对话框,如果用户点击模态外,我想关闭它。 I have written the following useEffect code but I run into following issue: 我写了以下useEffect代码,但我遇到了以下问题:

The modal dialog contains a number of children (React Nodes) and those children might change (eg the user deletes an entry of a list). 模态对话框包含许多子节点(React Nodes),并且这些子节点可能会更改(例如,用户删除列表的条目)。 Those interactions trigger my onClick method but as the clicked list item has been removed from the modal, the modal closes even though the click was within the modal. 这些交互触发了我的onClick方法,但是当点击的列表项已从模态中删除时,即使点击位于模态内,模态也会关闭。

I thought adding [ children ] at the second parameter for useEffect would cleanup the old effect event listener quick enough that the method does not run again but this is not the case. 我想在useEffect的第二个参数中添加[children]会足够快地清理旧的效果事件侦听器,使得该方法不会再次运行,但事实并非如此。

I handled the same issue in a class component with a ignoreNextClick -state but there must be a cleaner solution, right? 我在带有ignoreNextClick -state的类组件中处理了同样的问题但是必须有一个更清洁的解决方案,对吧?

    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 ] );

You can check parent of modal from the event.target . 您可以从event.target检查模态的父级。 If the current target is within the modal then return . 如果当前目标在模态内,则return

You can use closest to do that. 你可以使用最近的那样做。

See the following solution. 请参阅以下解决方案。

...

    if (event.target.closest( '.singleton-modal' ) || event.target.classList.contains('singleton-modal')) {
       return;
    }

...

I found a solution that does not require any sort of storing old props. 我找到了一个不需要任何存储旧道具的解决方案。

The useEffect call looks like this: useEffect调用如下所示:

useEffect( () => {
        const onClickOutside = () => onCloseModal();
        window.addEventListener( 'click', onClickOutside, false );
        return () => window.removeEventListener( 'click', onClickOutside );
    }, [] );

Adding the following click listener to the modal directly will stop the window click-listener from being called if the user clicked inside the modal. 如果用户在模态内部单击,则直接将以下单击侦听器添加到模态将停止调用窗口单击侦听器。

<div
    className={`modal ${ classes }`}
    onClick={event => event.stopPropagation()}
    role="presentation"
>
   {children}
</div>`

I also added the role presentation to make the modal more accessible and aria-conform. 我还添加了角色演示,以使模式更易于访问和符合Aria。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM