

import { createPortal } from 'react-dom';
import styled from 'styled-components';
import usePortal from '../../hooks/usePortal';
const PortalContainer = ({ isVisible, id, children }) => {
const target = usePortal(id);
// 주어진 id로 포털 부모 요소를 얻음
return createPortal(
// React 내장 함수인 createPortal은 두 개의 인자를 받음.
isVisible ? <Container>{children}</Container> : null,
// 1.렌더링할 컴포넌트
target,
// (포털의 부모 DOM 요소) 2. 타겟 돔 노드
);
};
export default PortalContainer;
// 변수 선언 후 내보내기
const Container = styled.div`
border: 1px solid black;
`;
React 포털은 React 컴포넌트 트리 바깥의 DOM 노드에 React 컴포넌트를 렌더링할 수 있게 해준다. 일반적으로 React 컴포넌트는 부모 컴포넌트의 DOM 구조 안에 렌더링되지만, 포털은 이를 무시하고 지정된 DOM 노드에 렌더링한다.부모 컴포넌트의 dom 구조에 영향을 주지 않는다. 즉, 모달, 드롭다운 같은 UI 컴포넌트를 구현할 때 유용하며, z-index와 CSS 레이아웃 문제를 피할 수 있다.
usePortal은 특정 id를 가진 DOM 노드를 반환하는 커스텀 훅이다.
id="modal-root"로 지정된 HTML 요소를 찾아서 포털의 렌더링 대상 노드로 사용한다.
ConfirmModal은 PortalContainer를 사용하여 모달을 렌더링한다.
export default function ConfirmModal({ isOpen, closeModal, onConfirm, ModalMessage }) {
return (
<PortalContainer isVisible={isOpen} id="modal-root">
<ModalBackdrop onClick={closeModal} />
<Container>
<ModalText>{ModalMessage}</ModalText>
<ButtonContainer>
<ConfirmButton onClick={onConfirm}>확인</ConfirmButton>
<CancelButton onClick={closeModal}>취소</CancelButton>
</ButtonContainer>
</Container>
</PortalContainer>
);
}
PortalContainer는 usePortal(id)로 포털을 렌더링할 DOM 노드(modal-root)를 찾음.
createPortal을 사용해 children을 modal-root에 렌더링.
ConfirmModal은 PortalContainer를 감싸면서 UI(모달)를 구성.