본문 바로가기
React/Example

React - Modal만들기(이벤트 버블링 차단)

by 로터스233 2023. 4. 16.

구현할 예제

알림창을 띄울 , 로그인 입력값을 받아야할 여러 상황에서 자주 쓰이는 모달을 구현해보고자 합니다.

 

1. modal component

'open modal' 버튼에 onClick 이벤트를 적용하고, 버튼을 클릭하면 showModal 값이 true 바뀌도록 상태관리를 해줍니다. showModal true 되면 Modal 등장하겠죠?

const [showModal, setShowModal] = useState(false);

const onShowModal = () => {
  setShowModal(true);
};

const onHideModal = () => {
  setShowModal(false);
};

return (
    <div className={styles.container}>
      <button className={styles.modalButton} onClick={onShowModal}>
       Open Modal
      </button>
      {showModal && <div className={styles.modal}>
        <div className={styles.box}>
         <button onClick={onHideModal}>x</button>
         <span>HELLO WORLD</span>
        </div>
       </div>}
    </div>
);

 

2. CSS

모달이 열리도록 했으니, css를 적용해야 합니다. 부모클래스의 position은 relative로 주고, 자식 클래스 position은 absolute로 하면 부모의 영역 안에서 자식의 위치를 top, left, right, bottom값으로 조정할 수 있습니다.

modal처럼 부모클래스의 영역을 전부 이용하고 싶다면 width, height 모두 100% 설정하면 됩니다.

.container {
    border: 1px solid grey;
    position: relative;
    width: 100%;
    height: 100vh;
}

.modal {
    width: 100%;
    height: 100%;
    background-color: #00000080;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    border-radius: 8px;
}

.box {
    width: 50%;
    height: 50%;
    background-color: white;
    border-radius: 10px;
}

 

3. modal 바깥을 클릭 했을 때 닫히도록 만들고 싶다면? 이벤트 버블링 차단하는 메소드 사용하기

1) 모달이 열린 상태에서 클릭 이벤트가 일어났을 때 그 영역이 어디인지 확인하고, 만약 모달 바깥이라면 닫히도록 하는 방법과, 2) event.stopPropagation()을 이용해 간단하게 처리하는 방법이 있습니다. (참고 : https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation)

 

첫번째 방법은 전역에서 클릭이벤트가 발생하는 것을 감지해야 하므로, 비효율적으로 생각되어 두번째 방법을 이용했어요.

 

stopPropagation외에도 stopImmediatePropagation(https://developer.mozilla.org/en-US/docs/Web/API/Event/stopImmediatePropagation)를 사용할 수 있는데요.

주의할 점은 stopPropagation은 상위의 모든 이벤트 버블링을 차단하지만, stopImmediatePropagation은 같은 레벨의 다른 모든 이벤트도 동작하지 않도록 차단한다는 것이예요. 둘의 차이점을 알고 적절하게 사용하면 좋을 것 같네요.

 

아래처럼 부모요소에는 modal을 닫는 함수를 걸고,

자식요소에서 이벤트 버블링을 차단한다면 shadow처리되는 영역을 클릭했을 때 모달이 닫히게 됩니다.

<div onClick={() => onHideModal()}>
  <div onClick={(e) => e.stopPropagation()}>
    <div>
        <span>{title}</span>
        <div onClick={() => onHideModal()}>
          <span>close</span>
        </div>
    </div>
    {children} // 모달 contents
  </div>
</div>