簡體   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