문제의 발단
프로젝트를 진행하면서 react-modal 라이브러리를 사용하고 있었습니다.
react-modal
Accessible modal dialog component for React.JS. Latest version: 3.16.1, last published: 2 years ago. Start using react-modal in your project by running `npm i react-modal`. There are 2821 other projects in the npm registry using react-modal.
www.npmjs.com
분명히 ESC Key를 통해서는 Modal창이 닫히는데
Modal창의 외부를 클릭했을 때는 Modal창이 닫히지 않는 문제가 발생했습니다.
실제로 부딪힌 사례를 보며 어떻게 문제를 해결했는가 살펴봅시다
function PreBox({ data }) {
const [isModalOpen, setModalOpen] = useState(false);
const openModal = () => {
setModalOpen(true);
};
const closeModal = () => {
console.log("Request Close!")
setModalOpen(false);
};
return (
<div className="pre-box" onClick={openModal}>
<div className="pre-box-container">
<img className="pre-img" src={`http://localhost:3000/api/imgs/${data.imagePath}`} alt="이미지"></img>
<div className="pre-title">{data.title}</div>
</div>
<Modal isOpen={isModalOpen} onRequestClose={closeModal} contentLabel="Program Modal">
<h1>{data.title}</h1>
<hr/>
<div className="modal-content">
<img className="modal-image" src={`http://localhost:3000/api/imgs/${data.imagePath}`} alt="Image" />
<div className="modal-info">
<p>{data.summary}</p>
<DownButton filepath={data.filePath} filename={data.title}/>
<div className="comment-container">
</div>
</div>
</div>
</Modal>
</div>
);
다음은 React Hook을 이용하여 Props값을 받아와 Modal창을 열어
받아온 데이터를 보여주는 컴포넌트 입니다.
Modal 컴포넌트의 props를 살펴보면 useState 훅을 이용해
모달창의 open, close를 관리하는 것을 볼 수 있습니다.
Modal 컴포넌트의 onRequestClose를 살펴보면
Mouse Event와 KeyboardEvent를 통해 Modal 창을 닫는 경우(default값으로 모달 외부 클릭, ESC 입력)
인자로 넘긴 함수를 실행하여 사용자에게 리렌더를 해줍니다.
문제는 MouseEvent에서 발생한 것 같았습니다. (KeyboardEvent는 정상작동하기 때문에)
한참을 고민하다가 모달창 상위요소에 MouseEvent가 있음을 확인할 수 있었습니다.
<div className="pre-box" onClick={openModal}>
<Modal isOpen={isModalOpen} onRequestClose={closeModal} contentLabel="Program Modal">
Event bubbling은 특정 요소에서 이벤트가 발생했을때
해당 요소의 부모 요소가 지닌 이벤트 핸들러까지 호출되는 현상을 말합니다.
모든 이벤트에서 발생하는 것은 아니지만 이것은 다음에 다루는 걸로
요약하자면 Modal 컴포넌트에서 일어난 Click이벤트가
div요소의 onClick 이벤트까지 호출되어 closeModal을 호출하고
바로 openModal을 호출한 것이지요!
거품이 아래에서 수면위로 올라가듯이
이벤트가 최상위 요소까지 호출되는 현상인 것이지요
그러면 어떻게 Event bubbling을 방지할 수 있을까요
Event Bubbling 방지
1. 하위 요소가 아닌 병렬 구조로 설정
<div className="pre-box">
<div className="pre-box-container" onClick={openModal}>
<img className="pre-img" src={`http://localhost:3000/api/imgs/${data.imagePath}`} alt="이미지"></img>
<div className="pre-title">{data.title}</div>
</div>
<Modal isOpen={isModalOpen} onRequestClose={closeModal} contentLabel="Program Modal">
onClick Event를 pre-box가 아닌 pre-box-container로 옮겨줌으로서
Modal 컴포넌트의 이벤트 버블링을 막을 수 있게 됩니다.
2. Event Bubbling 자체를 막는 법
<div onClick={(e) => e.stopPropagation()}>
해당 event Method를 사용하여 컴포넌트를 감싸면
더 이상 이벤트 버블링이 발생하지 않고 해당 target 요소 안에서 이벤트 핸들링이 끝낼 수 있습니다.
결론
1.Event Bubbling은 부모 요소에서 동일한 이벤트가 전달되어 실행되는 것을 의미한다
2.Event Bubbling을 event.stopPropagation() 메소드를 통해 막을 수 있다 (병렬구조로 만들면 상관없다)
아무 생각없이 JSX 구조를 짜다보면 이런 경우가 발생할 수 있음을 배웠습니다,,
오랜시간 고민하다 허무하게 해결되는 것을 보며 웹구조를 이해하는 것의 중요성을
다시금 느끼며 이것이 생산성에 얼마나 큰 문제를 주는지 느낍니다
'Web > JavaScript' 카테고리의 다른 글
TypeScript, 특수 타입 (0) | 2025.02.10 |
---|---|
Trouble Shooting, ActiveX z-index (0) | 2024.08.06 |
React.js, Skeleton Component 구현 (1) | 2024.04.18 |
JavaScript, 프로토타입 메서드 (0) | 2024.04.04 |
JavaScript, HTML Element와 상속체인 (0) | 2024.04.03 |