본문 바로가기
React.js

React 모달 밖 영역 클릭시 닫기 (2가지 방법)

by whoyoung90 2023. 10. 10.
반응형

> useState 사용

모달 바깥 부분(OutModal)에 투명한 배경을 뷰포트 크기로 깔고 이곳을 클릭했을때 모달을 닫아준다.

여기서 중요한점은

모달(DetailModal)과 모달 바깥 부분(OutModal)은 "형제"여야 하고,

모달의 z-index가 모달 바깥 부분보다 더 높아야한다.
즉 모달과 모달 바깥 부분은 다른 층에 존재하는 것이다. (이벤트 버블링을 막기 위해서!)

// 모달을 사용하는 컴포넌트
function Container() {
  const [modal, setModal] = useState(false);
  
  const openModalPopup = () => {
    setModal(true);
    document.body.style.overflow = "hidden";
  };
  const closeModalPopup = () => {
    setModal(false);
    document.body.style.overflow = "";
  };

  return (
    <Button onClick={openModalPopup}>모달 열기</Button>
    {modal &&
      <ModalComponent close={closeModalPopup} />
    })
}
// 모달 컴포넌트
function ModalComponent({ close } : { close: () => void }) {
  return (
    <ModalWrapper>
      <OutModal onClick={close}></OutModal>
      <DetailModal>
        모달창
      </DetailModal>
    </ModalWrapper>
  )
}

// 모달밖영역과 모달은 형제여야한다.
// 모달밖영역이 모달을 감싼다면 밖이 아니라 모달을 클릭해도 모달이 닫힌다. <이벤트버블링>

const OutModal = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 101;
`;

const DetailModal = styled.section`
  // ...
  z-index: 102;
`;

 

> target과 currentTarget 사용

target: 이벤트가 발생한 요소 (클릭한 바로 그것)
currentTarget: 이벤트 리스너(EventListener)를 가진 요소 (이벤트를 실행하는 바로 그것)

 

모달 전체를 감싸고 있는 ModalWrapper와 모달창 DetailModal으로 예를 들자면,

<ModalWrapper onClick="clickEvent">
  <DetailModal>
    모달창
  </DetailModal>
</ModalWrapper>

모달창 클릭시

- target 👉 DetailModal
- currentTarget 👉 ModalWrapper

 

모달 바깥 영역 클릭시

- target 👉 ModalWrapper
- currentTarget 👉 ModalWrapper

 

즉. 모달창 자체를 클릭했을 때 모달 바깥 영역에 있는 이벤트가 발생하지 않도록 하려면?

target과 currentTarget을 일치하는 경우만 이벤트를 발생시키면 된다!!

// 모달을 사용하는 컴포넌트
function Container() {
  const [modal, setModal] = useState(false);
  
  const openModalPopup = () => { ... };
  const closeModalPopup = () => { ... };
  
  // currentTarget을 지정하기 위한 useRef()
  const modalRef = useRef<HTMLDivElement>(null);
  const modalOutSideClick = (e: React.MouseEvent) => {
    if (modalRef.current === e.target) {
      setModal(false);
    }
  };

  return (
    {modal &&
      <ModalComponent
        modalRef={modalRef}
        modalOutSideClick={modalOutSideClick}
      />
    }
  )
}
// 모달 컴포넌트
interface propsType  {
  modalRef: React.ForwardedRef<HTMLDivElement>;
  modalOutSideClick:(e: React.MouseEvent) => void;
}

function useStatementModal({ modalRef, modalOutSideClick }: propsType) {
  return (
    <ModalWrapper ref={modalRef} onClick={(e) => modalOutSideClick(e)}>
      <DetailModal>
        모달창
      </DetailModal>
    </ModalWrapper>
  )
}

 

이벤트 버블링이란?

이벤트 버블링은 이벤트 발생 요소에서부터 순서대로 최상위 부모 요소까지 이벤트가 거품이 터지듯 연달아 발생하는 것!

 

[참조 URL]

https://velog.io/@leejpsd/React-%EB%AA%A8%EB%8B%AC%EC%98%81%EC%97%AD-%EB%B0%96-%ED%81%B4%EB%A6%AD%EC%8B%9C-%EB%8B%AB%EA%B8%B0

반응형

댓글