モード領域の外部をクリックしてモードを閉じる


🤯 質問する


オープンプロジェクトは、何か感じがあれば、私たちはかなりの精力を費やして実現したと思います...つまり、思った以上に意外なところで、気づかなかったミスを発見するということです.
たとえば、

...!!! 🥲


コメント内のより多くのビューをコンポーネントに分離し、より多くのビューを展開するかどうかを状態にして、コメントごとに管理するという問題が発生しました.他のコメントの「もっと」をクリックしても、以前クリックした「もっと」を無効にすることはできません!

🤔 検索方法


[その他のビュー]アイコン(true)をクリックして[申告/削除モード]を開き、この状態で[外部]をクリックするとモードが無効になり、モードが消えます.要するに、状態は再びfalseに変わるべきである.
Google検索でモードエリア外をクリックしてモードをオフにする方法は2つあります.
1.外部領域全体をラップした後(ModalBackdrop)、モードがアクティブになったら外部をクリックしてモードを無効にします.
export default function DropdownMenu() {
  const [openDropdown, setOpenDropdown] = useState<boolean>(false);
  
  const openDropdownHandler = () => {
      setOpenDropdown(false);
  }
  
  return (
    <>
      <DropDownWrap>
        {openDropdow && (
         <ModalBackdrop onClick={openDropdownHandler}>
           <MenuList>
             <div>수정</div>
             <div>삭제</div>
           </MenuList>
         </ModalBackdrop>
         )}
      </DropDownWrap>
    </>
  );
}
  • userRefを使用してゾーン外部を選択し(ModalBackdrop)、モードがアクティブな場合はイベントターゲットが外部refの場合はモードを無効にします.
  • export default function DropdownMenu() {
      const [openDropdown, setOpenDropdown] = useState<boolean>(false);
      const outSection = useRef<HTMLDivElement>(null);
      
      const openDropdownHandler = (event: React.MouseEvent<HTMLDivElement>) => {
        if (outSection.current === event.target)
          setOpenDropdown(false);
      }
      
      return (
        <>
          <DropDownWrap>
            {openDropdow && (
             <ModalBackdrop ref={outSection} onClick={openDropdownHandler}>
               <MenuList>
                 <div>수정</div>
                 <div>삭제</div>
               </MenuList>
             </ModalBackdrop>
             )}
          </DropDownWrap>
        </>
      );
    }
    我々のプロジェクトでは、上記の2つの方法は使用されていません.計算が完了したため、より多くのビューアイコンにposition: absoluteで表示されるため、外部領域をバンドルすることはできません.
    そうすれば.

    appsoluteでは、ドロップダウンメニューが右端に貼られているので、どのくらい離れているかを正確に計算する必要がありますが、反応型にして計算するのは難しいし、成功する保証はありません.
    だからよく考えてみると、そのドロップダウンモードが開いたとき、
    「外のクリックが感じられるのでは?」
    外をクリックしたときに開いた状態をfalseにして閉じるといいです!
    そう思ったのはaddEventListener.

    🛠 解決する


    現在、私の問題は素子内でonClickで解決できないので、現在位置の素子バーをクリックすると、クリックイベントが受信できる必要があります.そのためwindow.addEventListener('click', ...)を使用した.
    要素自体がレンダリングされると、openDropdownがオンになると、イベントリスナーはuseEffectにラップされ、それが実行される.1回目のレンダリング時に無条件に実行!
    export default function DropdownMenu() {
      const [openDropdown, setOpenDropdown] = useState<boolean>(false);
      
      const openDropdownHandler = () => {
          setOpenDropdown(false);
      }
      
      useEffect(() => {
        if (openDropdown) {            // 모달이 열려 있으면
          window.addEventListener(
            'click',                   // 클릭이 일어났을 때
            () => {
              setOpenDropdown(false);  // 모달을 닫는다!
            },
            { once: true },            // 한번만 실행되며 기억되지 않음 
          );
        }
      });
    { once: true }に設定されている条件はwindowで上のイベントリスナーを覚えているのでその条件は設定されておらず、実行するときだけ、最初の1回は起動していましたが、モードが閉じて再度押すと、開かない!
    また、モードリスト内では、stopPropagationを歩いて、クリックイベントは受け付けられません!では外をクリックするだけでモードがオフになります!😂

    🛠 コード#コード#

    export default function DropdownMenu() {
      const [openDropdown, setOpenDropdown] = useState<boolean>(false);
      
      const openDropdownHandler = () => {
          setOpenDropdown(false);
      }
      
      useEffect(() => {
        if (openDropdown) {        
          window.addEventListener(
            'click',        
            () => {
              setOpenDropdown(false);
            },
            { once: true },         
          );
        }
      });
      
      return (
        <>
          <DropDownWrap>
            {openDropdow && (
               <MenuList onClick={(e) => e.stopPropagation()}>
                 <div>수정</div>
                 <div>삭제</div>
               </MenuList>
             </ModalBackdrop>
             )}
          </DropDownWrap>
        </>
      );
    やっとできた...🤯
    グーグルをあちこちで遊びながら、いろいろな方法を学びました.
    でもできなかったら、眠れないかもしれないので、少し探してみたかったのですが、その日が終わってよかったです.休む.😭
    でも、今ブログで整理しているときに思いついたのは…では、そのビューをクリックするたびにuseEffectを実行してレンダリングしますか?!今は文字だけなのであまり負担はありませんが、後で画像やgifを入れることができれば...🤷‍♀️ △それなら、考えてみましょう.
    リファレンス
    https://dkmqflx.github.io/frontend/2021/04/26/react-modal-close/
    https://white-salt.tistory.com/25
    https://developer.mozilla.org/ko/docs/Web/API/EventTarget/addEventListener
    https://pa-pico.tistory.com/20