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

IT技术 javascript reactjs react-hooks use-effect
2021-05-22 08:17:42

我有一个模态对话框,如果用户在模态之外单击,我想关闭该对话框。我编写了以下 useEffect 代码,但遇到以下问题:

模态对话框包含许多子节点(react节点),这些子节点可能会发生变化(例如,用户删除列表中的一个条目)。这些交互会触发我的 onClick 方法,但是由于单击的列表项已从模态中删除,即使单击在模态内,模态也会关闭。

我认为在 useEffect 的第二个参数中添加 [ children ] 会足够快地清理旧的效果事件侦听器,使该方法不再运行,但事实并非如此。

我在一个带有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 ] );
2个回答

我找到了一个不需要任何存储旧props的解决方案。

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>`

我还添加了角色介绍,以使模态更易于访问和符合 aria。

您可以从event.target. 如果当前目标在模态内,则return.

你可以使用最接近来做到这一点。

请参阅以下解决方案。

...

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

...