ReactDOM에서 제공하는 Portal은 컴포넌트를 렌더링 할 때, 부모 컴포넌트의 DOM 외부에 존재하는 DOM 노드에 렌더링 할 수 있게 해준다.
풀어서 설명하자면
Portals는 리액트 프로젝트에서 컴포넌트를 렌더링하게 될 때, UI를 어디에 랜더링 시킬지 DOM을 사전에 선택하여 부모 컴포넌트의 바깥에 렌더링 할 수 있게 해주는 기능이다.
즉, DOM의 계층구조 시스템에 종속되지 않으면서 컴포넌트를 렌더링 할 수 있다!
이 기능은 Modal 컴포넌트를 만들어야 될 때 매우 유용하게 사용 할 수 있다.
리액트 프로젝트 엔트리 파일인 index.js 부분에 "modal-root" 설정
<body>
<div id="root"></div>
<div id="modal-root"></div>
</body>
import * as ReactDOM from 'react-dom'
const $portal = document.querySelector('#modal-root')
const Modal = ({ children, isShowing, close }) => {
return isShowing && $portal
? ReactDOM.createPortal(
<S.ModalWrapper className={'modal-container'} onClick={close}>
<div className={'contents'}>{children}</div>
</S.ModalWrapper>,
$portal,
)
: null
}
export const ModalWrapper = styled.div`
display: flex;
justify-content: center;
align-items: center;
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
background: rgba(0, 0, 0, 0.4); // 바깥 배경 밝기
z-index: 10;
`
export default Modal
import { useState } from 'react'
const useModal = (initShow = false) => {
const [isShowing, setIsShowing] = useState(initShow)
const toggle = (eventOrBool) => {
if (typeof eventOrBool === 'boolean') {
setIsShowing(eventOrBool)
return
}
const target = eventOrBool.target
if (target.closest('.close')) {
setIsShowing(!isShowing)
return // close 클릭시 종료
}
if (target.closest('.contents')) {
return // 안 contents 클릭시 유지
}
setIsShowing(!isShowing) // 그 외 종료
}
return { isShowing, toggle }
}
export default useModal
코드참고
src > components > base > Modal