React Portal로 modal 만들기

pds·2022년 12월 12일
0

TIL

목록 보기
25/60

React Portals

  • Portal 은 부모 컴포넌트 DOM 계층 구조 바깥에 있는 특정 DOM으로 자식을 렌더링 시켜주는 방법을 제공함
ReactDOM.createPortal(child, container)

child: Element,문자열,Fragment 같은 렌더링할 수 있는 React 자식
container: 넣으려는 DOM Element

render() {
  // 새로운 div를 생성하지 않고 `domNode` 안에 자식을 렌더링함
  return ReactDOM.createPortal(
    this.props.children,
    domNode
  );
}

왜 필요

  • JSX 컴포넌트는 React.createElement 로 변환되며 반드시 하나만 가짐

  • 루트 JSX 컴포넌트는 반드시 하나여야 하고 자식 노드는 반드시 안에 포함된다.

  • <div><> 등으로 감싸서 하나로 만들 수 있지만 불필요하게 너무 많아질 수 있음

  • 의존관계 떄문에 그러지 않고 싶어도 특정 dom 내부 깊숙히 위치하게 되는 노드가 있게 된다.

modal 같은 것들도 특정 이벤트로 발생하게 되기에 특정 컴포넌트 안에서 prop을 받아야 하는 상태임


해당 Dom 내부에 있지 않지만 Event Bubbling은 가능

  • 포탈이 어디 이상한 DOM 노드에 존재해도 다른 일반적인 react 컴포넌트 처럼 동작한다.

  • DOM트리의 위치와 상관없이 포탈은 해당되는 react 트리 내에 존재하는 것으로 치기 때문임

눈에 보이는 DOM트리와 React의 Virtual DOM 트리는 구분되어있다.

  • 따라서 React트리에서는 부모 컴포넌트로부터 전파되는 이벤트나 프로퍼티를 적절하게 얻을 수 있게 된다.

주로 어디 쓸까?

portal의 전형적인 유스케이스는 부모 컴포넌트에 overflow: hidden이나 z-index가 있는 경우이지만, 시각적으로 자식을 “튀어나오도록” 보여야 하는 경우도 있습니다. 예를 들어, 다이얼로그, 호버카드나 툴팁과 같은 것입니다.

  • modal, tooltip 같은 갑자기 튀어나오는 요소들에 사용된다.

부모 밑에 존재할 때 z-index, overflow:hidden 같은 속성이 있어 방해를 받아 제 역할을 못할 여지가 있기 때문이다


모달 만들기

  <div id="modal-root"></div>

index.html에 이런식으로 순간이동 시킬 위치를 지정해주었다.


export default function App() {
  const [visible, setVisible] = useState(false);
  return (
    <div className="App">
      <h1>Hello Portal</h1>
      <p>모달모달</p>
      <button onClick={() => setVisible(true)}>모달열기</button>
      <Modal visible={visible} onClose={() => setVisible(false)}>
        <h2>안녕나는모달이야</h2>
        <button onClick={() => setVisible(false)}>닫을랭</button>
      </Modal>
    </div>
  );
}

위처럼 <App/> 의 특정 돔 내부에 위치하지만 실제로는 그렇지 않다.

덤으로 useClickAway hook을 만들어서 모달 바깥을 클릭할 때 닫힐 수 있는 이벤트도 처리해주었다.



Ref

profile
강해지고 싶은 주니어 프론트엔드 개발자

0개의 댓글