자식 컴포넌트(button)에서 JSX 표현식을 return하면, 자식 컴포넌트는 아래의 콘솔창처럼 부모 컴포넌트(root)의 내부에서 렌더링이 발생한다.

하지만 createPortal을 사용하면 자식 컴포넌트는 부모 컴포넌트에 종속되지 않고 다른 container 컴포넌트에서 렌더링을 할 수 있다. createPortal은 인자로 제공된 자식 컴포넌트 혹은 JSX 표현식을 부모 컴포넌트의 외부에서 렌더링하는 메서드이기 때문이다.
아래 콘솔창에 있는 <div class="modal-wrapper-root">엘리먼트와 <div id="root"> 엘리먼트는 형제 관계인 것처럼 보이지만, 실제 코드에서는 <div class="modal-wrapper-root">엘리먼트가 <div id="root"> 엘리먼트에 속한 부모 자식관계이다.

실제 코드를 살펴보자.
function ToastNotiParent() {
const [isOpen, setIsOpen] = useState(false);
return (
<>
<button onClick={handleButton}>on/off</button>
<ToastNotiChild open={isOpen} className='test'>
<div>test</div>
</ToastNotiChild>
</>
)
};
function ToastNotiChild({ open, className, children }) {
const modalLayout = useRef(null);
if (!open) {
return null;
}
return createPortal(
<div ref={modalLayout} className={`modal-wrapper-root ${className}`}>
<div className='toast-wrapper'>{children}</div>
</div>,
document.body
)
};
createPortal 메서드는 DOM tree에서 자식 컴포넌트를 부모 컴포넌트의 DOM 계층 구조 밖에 존재하는 DOM 노드에서 렌더링시킨다. 그렇다면 createPortal 메서드를 사용할 때 Context나 이벤트 위임은 어떤 식으로 처리가 되는 것일까?
결론부터 말하자면 React 내에서 컴포넌트가 동작하는 로직(Context 혹은 이벤트 버블링과 캡쳐링 등)은 일반적인 부모 자식 관계와 동일하다.
React는 이 때도 Virtual DOM을 활용하는데, 자식 컴포넌트에서 사용한 Portal의 개념(createPortal 메서드의 흔적 또는 코드상 위치)은 React tree(Virtual DOM tree)에 남아있고, react-dom 라이브러리가 Virtual DOM과 실제 DOM을 비교할 때 실제 DOM tree에서 자식 노드의 렌더링 위치가 변경되는 것이다.

참고
React 공식문서(Virtual DOM과 Internals)
ReactJS Virtual DOM and Reconciliation - Explain Like I'm Five
'개발' 카테고리의 다른 글
| 주소창에 google.com을 치면 발생하는 일 (0) | 2022.10.12 |
|---|---|
| MIME (0) | 2022.10.02 |
| JSX (0) | 2022.09.28 |
| React Context (0) | 2022.09.28 |
| React Router v6 (0) | 2022.09.25 |
댓글