진행하고 있는 프로젝트에서 모달창을 구현해야했었는데 모달창 구현은 여러번 해봤기떄문에 빠르게 구현을 완료했다.
그 후 react-portal로 모달창을 구현하면 렌더링 성능이 좋다는 얘기를 듣고 리팩토링을 시도했다.
react-portal은 자식 컴포넌트를 부모 컴포넌트 바깥에 있는 다른 컴포넌트에 전달할 수 있다.
음.. 자식 컴포넌트를 부모 컴포넌트 바깥에 전달하는거까지는 좋은데 그러면 왜 좋지?
어떤 점이 좋은지는 react의 리렌더링 방식을 보면 알 수있다.
부모트리가 바뀌게되면 그 밑에 자식트리도 함께 바뀌게 된다.
그렇다면 모달창 위의 부모트리가 계속 바뀐다면?
모달창까지 무분별하게 리렌더링될 수가 있다.
이것 외에도 modal창은 기능상 레이아웃 맨위에 있어야한다. 하지만?
구조상 아래에 있는 modal창은 따로 개발자가 z-index를 조절해가며 스타일 조작을 해야한다.
스타일 조작까지 오케이 근데 마지막으로 스크린리더가 모달창을 인식을 못한다고 한다. 왜냐하면 모달창은 html구조상 맨위에 존재해야하기 떄문이다.
이러한 이유들떄문에 react-portal를 쓰는것이다.
Portal은 보통, 다른 루트에 Modal, Dialog, Tooltip 등을 띄우기 위해 많이 사용된다.
굉장히 간단하다.
일단 내가 모달창을 소환?할 장소를 정해야한다.
modal창을 만들꺼기떄문에 나는 root 즉 최상단트리에 모달창을 포탈시킬것이다.
<body className={`${NotoR.className} ${NotoB.variable}`}>
<NavBar />
<ReactQueryProviders>{children}</ReactQueryProviders>
<Footer />
<div id="modal" />
</body>
</html>
일단 내가 모달창을 넣을 공간을 마련했다.
출구를 만들어놨으니 포탈의 기능을 추가해보겠다
import ReactDom from 'react-dom';
const ModalPortal = ({ children }: { children: React.ReactNode }) => {
const el = document.getElementById('modal') as HTMLElement;
return ReactDom.createPortal(children, el);
};
export default ModalPortal;
이 코드는 children Props 줄래? 그거 내가 너가 지정한 출구로 이동시켜줄게
라는 코드이다.
{isOpen && (
<ModalPortal>
<Modal
handleModal={handleModal}
creatorId={loginedId}
boardId={productInfo?.id}
/>
</ModalPortal>
)}
아까 만들어둔 ModalPortal안에 children을 넣자
이 children은 출구로 나올 코드이다.
그러면 완성 !


root에 있는 div가 반짝반짝 거리는걸 볼 수 있다.
미세하게 렌더링의 성능과 을 높였고 시멘틱 규칙을 준수했다.