🔥 문제
MainContainer
가 클릭이 불가능한 현상이 발견되었다. 따라서 아무리 카드를 클릭해도 이벤트가 발생하지 않는다. 이유가 무엇일까?⭐ 해결 방법
약 1시간을 거쳐 확인해 보니, 원인은
React.createPortal
때문이었다.리액트 공식 문서에는 다음과 같이
React.createPortal
을 설명한다.portal의 전형적인 유스케이스는 부모 컴포넌트에overflow: hidden
이나z-index
가 있는 경우이지만, 시각적으로 자식을 “튀어나오도록” 보여야 하는 경우도 있습니다. 예를 들어, 다이얼로그, 호버카드나 툴팁과 같은 것입니다. portal이 DOM 트리의 어디에도 존재할 수 있다 하더라도 모든 다른 면에서 일반적인 React 자식처럼 동작합니다. context와 같은 기능은 자식이 portal이든지 아니든지 상관없이 정확하게 같게 동작합니다. 이는 DOM 트리에서의 위치에 상관없이 portal은 여전히 React 트리에 존재하기 때문입니다.
오호, 그렇다면 잘 생각해보자.
Modal
은 현재 MainContainer
의 자식으로 종속되어 있을 것이다. 따라서, 이벤트 버블링은
MainContainer
의 자식처럼 발생할 것이다.const [el, setEl] = useState<HTMLDivElement | null>(null); useEffect(() => { setEl(() => document.querySelector('.main-container)); }, []); useEffect(() => { if (el) document.body.appendChild(el); return () => { if (el) document.body.removeChild(el); }; }, [el]);
그러면, 현재
Modal
은 포지션이 무엇인가? fixed
이다.그런데 아까 위의 인용을 잘 보자. Portal은 어찌했건 간에 React Tree안에 종속되어 있다.
React Tree에는 아마, CSSOM과 DOM Tree가 합쳐진 attanchment 과정의 산물이 포함되어 있을 것이다.
그런데,
fixed
에는 괴상한 특징이 존재한다. absolute
와 달리 아예 화면 자체에서 컨트롤하는 습성이 있다.따라서, 아예 클릭이 되지 않았던 것이다.
진짜 해결 방법 - document
의 부모를 바꿔버리자.
아주 간단한 해결 방법은, 그냥 아예 독단적인 애라고 처리하는 것이었다.
즉, 부모를 아예 바꿔버리는 것이다.
애초부터 부모에서의 자식 속성인 것처럼 이벤트 버블링이 안 일어나도록 하면 되는 것 아니겠는가.
따라서
display
에서만 fixed
의 속성이 진가를 발휘하도록 부모 컴포넌트를 아예 body
의 자식 컴포넌트로 만들어줬다.이렇게 하면, 이제 아예 별개의 컴포넌트이므로, 정상적으로 동작할 수 있을 것이다.
const [el, setEl] = useState<HTMLDivElement | null>(null); useEffect(() => { setEl(() => document.createElement('div')); }, []); useEffect(() => { if (el) document.body.appendChild(el); return () => { if (el) document.body.removeChild(el); }; }, [el]); if (!el) return null; return createPortal( <BackgroundDim style={{ display: visible ? 'block' : 'none' }}> <MainContainer as="div" paddingWidth={24}> <ModalContainer width={width} height={height} padding={padding} ref={ref} {...props} > {children} </ModalContainer> </MainContainer> </BackgroundDim>, el ); }; export default Modal;
결과
잘 동작한다!

배운 점
단순히 라이프사이클이 아니라, 리액트 트리에서의 동작 원리까지 익혀야 했던 어려운 순간이었다.
시간도 많이 들었다. 그렇지만, 결국
React Tree
에서는 attachment
의 결과물을 자신들의 해석에 따라 컨틀로 하고 있다는 확신이 들었고, 이를 나중에 여유 시간이 되면 좀 더 살펴 보아야겠다고 생각했다.