치춘짱베리굿나이스
react-portal 사용해보기 본문
react-portal
부모 컴포턴트의 바깥에 있는 DOM 노드에 자식을 렌더링할 수 있는 기능이다
쉽게 말하면! 리액트에서 모든 컴포넌트는 root
에 렌더링이 되는데, react-portal을 이용하면 root
밖에 있는 요소에도 컴포넌트를 렌더링할 수 있다는 것이다
이렇게... modal
태그는 root
의 밖에 있음에도 마치 root
안에 있는 것처럼 연결해주는 것이다
마치 게임에 나오는 포탈처럼 말이다
react-portal 써보기
1. index.html 파일의 root 태그 바깥에 요소 끼워넣기
...
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="modal"></div>
</body>
</html>
리액트는 root
요소 안에만 요소를 렌더링함을 기억하고, 완전 바깥에 modal
요소를 넣어보자
이렇게 html 파일 안에 요소를 끼워넣으면, 요소가 존재하지 않는 경우가 없으므로 document.getElementByID()
를 통해 요소를 가져와도 오류가 나지 않는다
정 찝찝하면 useRef
써도 상관 없다
2. document.getElementByID로 요소 가져오기
import ReactDom from 'react-dom';
interface IPortalType {
children: React.ReactNode;
}
const ModalPortal = ({ children }: IPortalType): React.ReactPortal => {
const element = document.getElementById('modal') as Element;
return ReactDom.createPortal(children, element);
};
export default modalPortal;
document.getElementById()
를 통해 아까 body
태그에 끼워넣었던 modal
요소를 element
로 가져오자
이 element
로 향하는 포탈을 생성할 것이다
ReactDom.createPortal
함수는 포탈건과 비슷한 역할을 하며, 첫 번째 인자 children
을 두 번째 인자 element
안에 렌더링할 것이다
오늘만큼은 우리가 첼이다 부모 컴포넌트에 파란색 포탈, 자식 컴포넌트에 주황색 포탈을 열어보자
3. 자식으로 넣을 컴포넌트 만들기
export const Modal = ({ setIsHidden }: IModalType) => {
return (
<ModalPortal>
<div className={styles.modalBackground}>
<div className={styles.modalContainer}>
<header>컨텐츠1</header>
<main>컨텐츠2</main>
</div>
</div>
</ModalPortal>
);
};
간단하게 모달 컴포넌트를 작성한다
포탈이 걸린 요소 (element
) 의 자식으로 넣어줄 컴포넌트는 앞에서 작성했던 ModalPortal
함수로 감싸준다
진짜 모달처럼 보일 수 있도록 백그라운드도 그려주었다
모달 열림 / 닫힘 여부를 위해 상태값 설정하는 함수도 부모에게서 넘겨줘야 하지만 자세한 설명은 일단 생략하였다
4. Portal로 부모 - 자식 간 컴포넌트 연결
const [isModalOpen, setIsModalOpen] = useState(false);
...
return (
...
<ModalPortal>
{isModalOpen && (
<Modal
isFavorite={isFavorite}
setIsFavorite={setIsFavorite}
setIsModalOpen={setIsModalOpen}
movieData={movieData}
/>
)}
</ModalPortal>
...
)
모달을 렌더링하고 싶은 부모 컴포넌트에 ModalPortal
으로 감싼 자식 모달 컴포넌트를 심는다
이 ModalPortal
두 개가 포탈처럼 연결되어 자식 컴포넌트를 ModalPortal
에서 정의한 태그에 그려줄 것이다
모달의 열림 / 닫힘 여부를 판정하기 위해 isModalOpen
상태값을 사용하였고, true일 때만 모달을 열리게 한 뒤 모달을 닫기 위해 props로 setIsModalOpen
함수를 넘겨주었다
이렇게 해서 isModalOpen
의 값은 모달을 열고 닫는 버튼을 눌렀을때 핸들러 함수 내에서 변경된다
모달 안에서 버튼을 눌렀을 때 좋아요 여부도 바꾸기 위해 isFavorite
, setIsFavorite
상태값도 넘겨준다
모달을 열었을 때 root
div
하위의 modal
div
에서 모달을 렌더링하는 것을 볼 수 있다
결론
맨날 귀찮아서 모달 라이브러리 설치해다가 썼었는데, 기본 제공 기능인 Portal을 사용하니 생각보다 되게 쉽게 모달을 만들 수 있었고, 디자인 수정도 굉장히 쉬웠다
앞으로 굳이 라이브러리 설치 안해도 될 것 같다
참고자료
'ClientSide > React' 카테고리의 다른 글
React (0) | 2022.10.01 |
---|---|
useClickOutside 직접 구현하기 (0) | 2022.07.01 |
데이터 불러오기, Suspense (0) | 2022.05.13 |
IntersectionObserver + 무한스크롤 (0) | 2022.05.12 |
Custom Hook (0) | 2022.05.09 |