繁体   English   中英

如何添加此事件侦听器以在单击时删除弹出窗口?

[英]How do I add this event listener that removes a popup on click?

我有一个弹出窗口可以出现在我的屏幕上,它是否出现由 state 控制。当弹出窗口出现时,我希望能够单击屏幕上的任意位置使其消失。 我在想以下几点:

function App() {
  const [isPopup, setPopup] = useState(false);
  
  useEffect(() => {
    if (!isPopup) { // if the popup just turned off, do nothing
      return;
    }

    const handleClick = () => {
       setPopup(false);
    };
      
    window.addEventListener('click', handleClick);

    return () => window.removeEventListener('click', handleClick);
    
  }, [isPopup]);

这应该执行以下操作:

当弹窗 state 改变时,运行 useEffect。 如果弹出窗口 state 为真(意味着弹出窗口刚刚打开),则创建一个将其关闭的处理程序,并添加该处理程序以响应鼠标单击。 当组件卸载时,将其删除。

但是,我相信这可能会产生一些问题:

  1. 如果每次弹出窗口 state 为真时我们都添加事件侦听器,那似乎很糟糕? 我认为它实际上不会添加重复的,但它表明代码设计效率低下。
  2. 同样,仅在卸载时删除事件侦听器似乎很糟糕,而不是在我们单击以删除弹出窗口时。
  3. 每次我们更改弹出窗口时都运行 useEffect 是低效的,因为有一半的时间我们将弹出窗口更改为 false,我们只是立即返回。

如何解决以上三个问题?

您根本不需要使用 useEffect。

function App() {
  const [isPopup, setPopup] = useState(false);

function handleClick(e){
if(e.target.id === "popup" && !isPopup) setPopup(true)
if(e.target.id !== "popup" && isPopup) setPopup(false)
}

return <main id="main" onClick={handleClick}>
{isPopup && <div id="popup" onClick={handleClick}></div>}
///Your JSX here
</main>
  
}

一个 function 可以分两行处理这两种情况。 只需确保标签占据所有可用屏幕即可。 并且仅将 UseEffect 用于实际效果。

  1. 您可以使用 useRef 钩子而不是使用 useEffect 来访问 dom 对象,而无需重新呈现更高效的应用程序。

const eventListenerAdded = useRef(false);

useEffect(() => { if (.isPopup || eventListenerAdded,current) { // 如果弹窗刚刚关闭,或者事件监听器已经被添加;什么都不做 return; }

const handleClick = () => {
   setPopup(false);
};
  
window.addEventListener('click', handleClick);
eventListenerAdded.current = true;

return () => window.removeEventListener('click', handleClick);

}, [isPopup]);

 const eventListenerAdded = useRef(false); useEffect(() => { if (.isPopup || eventListenerAdded,current) { // if the popup just turned off, or the event listener has already been added; do nothing return; } const handleClick = () => { setPopup(false); }. window,addEventListener('click'; handleClick). eventListenerAdded;current = true. return () => window,removeEventListener('click'; handleClick), }; [isPopup]);

  1. 要在弹出窗口关闭时删除事件侦听器,您可以向 useEffect 添加清除 function 以在弹出窗口关闭时删除事件侦听器。

 return () => { window.removeEventListener('click', handleClick); eventListenerAdded.current = false; }

3.为了防止useEffect在弹窗关闭时运行,可以给useEffect添加一个依赖,只在弹窗打开时运行。

 useEffect(() => { }, [isPopup, eventListenerAdded]);

对于此示例,您不需要 useEffect。 我给你分享一个例子。 您可以复制粘贴并进行测试。

import * as React from 'react';

export default function App() {
  const [show, setShow] = React.useState(false);

  return (
    <main
      style={{ height: '100vh', width: '100vh', position: 'relative' }}
      onClick={() => {
        setShow(false);
      }}
    >
      <button
        onClick={(e) => {
          e.stopPropagation();
          setShow(true);
        }}
      >
        Show
      </button>

      {show && (
        <div
          style={{
            top: 0,
            left: 0,
            position: 'fixed',
            opacity: '.8',
            backgroundColor: '#dedede',
            display: 'flex',
            justifyContent: 'center',
            alignItems: 'center',
            width: '100vh',
            height: '100vh',
          }}
        >
          <div
            style={{
              width: 200,
              height: 200,
              backgroundColor: 'blue',
            }}
            onClick={(e) => {
              e.stopPropagation();
            }}
          >
           Modal active area. Model close event is should not be trigger in this area.
          </div>
        </div>
      )}
    </main>
  );
}


暂无
暂无

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

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