22sook00 logo
SookDev

React.Portal

tag
react
date
Nov 13, 2023
Portal은 부모 컴포넌트의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 렌더링하는 최고의 방법을 제공합니다. 이게 뭔소리야 ?
쉽게 말하자면, 리액트에서 우리는 가장 상위의 root div 아래에 프로젝트를 생성한다.
프로젝트에 모달을 띄우고 싶을때 모달 바깥의 부모가 z-index 라던가 overflow-hidden 등등 자식에게 영향을 주는 스타일이 있다고 가정할때, 스타일의 우선순위를 고려해야 한다.
리액트 포탈을 사용하면 아예 새로운 곳에 부모의 다른영역에 모달을 띄우면서 부모에 영향받지 않도록 하는것이다.
툴팁이나 모달에서 많이 사용한다.

사용예시

import { createPortal } from 'react-dom' const CardPopup = ({ ...props }) => { const ref = useRef() const [mounted, setMounted] = useState(false) useEffect(() => { setMounted(true) if (document) { const dom = document.getElementById('root-portal') ref.current = dom } // 배경 스크롤 막기 document.body.classList.add('hidden-scroll') return () => { // 현재 떠 있는 다이얼로그가 없을 떄 배경 스크롤 막기 해제 // #products-view 는 상품상세의 하단 고정바 이므로 제외하고 카운팅 if (document.querySelectorAll('#dialog-root > div:not(#products-view)').length === 0) { document.body.classList.remove('hidden-scroll') } } }, []) if (ref.current && mounted) { return createPortal( <SC.CardPopupLayer> <SC.PopupBackground onClick={handleClosePopup} /> ... </SC.CardPopupLayer>, ref.current ) } return null } export default CardPopup
//ReactDOM.createPortal(child, container) //index.html <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <div id="root-portal"></div> </body>
앞서 말했듯이 리액트의 모든 코드는 index.html 의 root div 하위에서 그려지고 있는데
의도적으로 root-portal 이라는 아이디를 새로운 도화지의 div 를 생성하여 모달을 그려주게 되는것이다.