영화나 소설을 보다 보면 포탈을 통해 다른 장소, 다른 세계로 이동하는 장면이 나온다.
다른 장소로 이동할 수 있는 포탈이 React에서도 존재한다.
React는 React로 랜더링 할 수 있는 것이라면 무엇이든, 개발자가 지정한 특정한 element의 자식 요소로 보낼 수 있는 Portal 기능을 제공한다.
import { createPortal } from 'react-dom';
const ComponentA=()=>{
//...
return (
<div>
<SomeComponent />
{createPortal(children, domNode)}
</div>
)
}
Portal을 사용하면, DOM list에서 children은 domNode의 자식 요소로 존재하게 되지만 이벤트는 React tree를 따라 전파된다.
즉, ComponentA component에서 "portal-root"라는 id를 가지는 element에 "portal"이라는 id를 가지는 Portal component를 Portal을 해주었다고 가정해보자
<div id="portal-root">
<div id="portal">
</div>
</div>
const ComponentA =()=>{
const [portal, setPortal]=useState(false);
const [data, setData] =useState("")
return(
<div>
{portal &&
<Portal data={data}/>
}
</div>
)
}
Portal component는 DOM list상으로는 "#portal-root"의 자식 요소이지만,
props준 ComponentA의 data 값이 변경되면 Portal 속 data 값도 변경이 된다.
React 공식 문서에서는 Portals이 활용될 수 있는 여러 상황에 대해 설명해놨다.
이 중에서도 Portal이 유용하다고 생각했던 것은 modal이다.
...
<div id="modal-root">
...
import React, {ReactNode } from 'react';
import * as reactDOM from 'react-dom';
type ModalProps ={
children:ReactNode
}
const Modal=({children}:ModalProps)=>{
const modalEl = document.getElementById("modal-root") as HTMLElement;
return reactDOM.createPortal(
<div className='modal'>
<div className="modal-background">
<div className="modal-box">
<div className="modal-inner">
{children}
</div>
</div>
</div>
</div>
,modalEl);
};
export default React.memo(Modal);
const App =()=>{
const [openModal, setOpenModal]=useState<boolean>(false)
return(
...
{openModal &&
<Modal>
<div>Open Modal</div>
</Modal>
}
)
}