React Hooks:模态事件监听器的useEffect
React Hooks: useEffect for modal event listener
我有一个模态对话框,如果用户在模态之外单击,我想将其关闭。我已经编写了以下 useEffect 代码,但我 运行 进入以下问题:
模态对话框包含许多子项(React 节点),这些子项可能会更改(例如,用户删除列表的条目)。这些交互触发了我的 onClick 方法,但由于已从模态中删除了单击的列表项,即使单击在模态内,模态也会关闭。
我认为在 useEffect 的第二个参数中添加 [children] 会足够快地清理旧的效果事件侦听器,以至于该方法不会再次 运行,但事实并非如此。
我在具有 ignoreNextClick
状态的 class 组件中处理了同样的问题,但必须有更清洁的解决方案,对吗?
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 ] );
您可以从 event.target
检查模态的父级。
如果当前目标在模态内,则 return
.
您可以使用 closest 来做到这一点。
请参阅以下解决方案。
...
if (event.target.closest( '.singleton-modal' ) || event.target.classList.contains('singleton-modal')) {
return;
}
...
我找到了一个不需要任何存储旧道具的解决方案。
useEffect 调用如下所示:
useEffect( () => {
const onClickOutside = () => onCloseModal();
window.addEventListener( 'click', onClickOutside, false );
return () => window.removeEventListener( 'click', onClickOutside );
}, [] );
直接将以下点击侦听器添加到模式将阻止 window click-listener 在用户单击模式内部时被调用。
<div
className={`modal ${ classes }`}
onClick={event => event.stopPropagation()}
role="presentation"
>
{children}
</div>`
我还添加了角色介绍,使模式更易于访问 aria-conform。
我有一个模态对话框,如果用户在模态之外单击,我想将其关闭。我已经编写了以下 useEffect 代码,但我 运行 进入以下问题:
模态对话框包含许多子项(React 节点),这些子项可能会更改(例如,用户删除列表的条目)。这些交互触发了我的 onClick 方法,但由于已从模态中删除了单击的列表项,即使单击在模态内,模态也会关闭。
我认为在 useEffect 的第二个参数中添加 [children] 会足够快地清理旧的效果事件侦听器,以至于该方法不会再次 运行,但事实并非如此。
我在具有 ignoreNextClick
状态的 class 组件中处理了同样的问题,但必须有更清洁的解决方案,对吗?
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 ] );
您可以从 event.target
检查模态的父级。
如果当前目标在模态内,则 return
.
您可以使用 closest 来做到这一点。
请参阅以下解决方案。
...
if (event.target.closest( '.singleton-modal' ) || event.target.classList.contains('singleton-modal')) {
return;
}
...
我找到了一个不需要任何存储旧道具的解决方案。
useEffect 调用如下所示:
useEffect( () => {
const onClickOutside = () => onCloseModal();
window.addEventListener( 'click', onClickOutside, false );
return () => window.removeEventListener( 'click', onClickOutside );
}, [] );
直接将以下点击侦听器添加到模式将阻止 window click-listener 在用户单击模式内部时被调用。
<div
className={`modal ${ classes }`}
onClick={event => event.stopPropagation()}
role="presentation"
>
{children}
</div>`
我还添加了角色介绍,使模式更易于访问 aria-conform。