07
12

대단한 기술을 하찮은 곳에 사용합니다. 하지만 가장 중요하죠.

1. 문제의 발단

  • 스타일 가이드를 고치면서 확인하니, z-index가 모든 alert, modal등에서 꼬여있다.
  • 가장 최상의 단위를 잡고, 위계를 생각하며 기획이 되어야 하지만 추가되는 사항이 많고, 리팩토링 하지 못 해서 꼬여있었다.
  • 그래서 임시로 추가할 alert에 z-index를 9999로 설정하고 만들었다.
  • 하지만 하위 노드에서 이미 modal을 만들고, 그것을 기준으로 다음 컴포넌트들을 만들어 z-index와 상관없이 최상위로 올라오지 않는 이슈가 있었다.
  • 그래서 아예 처음부터 가장 최상위에 올려서 렌더링 하기로 하였다.

2. Potal?

  • 지정한 DOM의 외부에 렌더링을 하게 만들어주는 함수
  • 첫 번째 인자에는 컴포넌트, 두 번째 인자로 DOM을 넣어준다.

3. 예시

import { Dispatch, SetStateAction, useEffect } from 'react';
import { createPortal } from 'react-dom';

export function Alert({
  children,
  setState,
}: {
  children: React.ReactNode;
  setState: Dispatch<SetStateAction<boolean>>;
}) {
  // useEffect로 timeout을 걸어 3초 뒤 자동으로 꺼지게 만든다.
  useEffect(() => {
    const timeout = setTimeout(() => {
      setState(false);
    }, 3000);

    // 다시 alert가 열리더라도, 처음 timeout을 초기화 하여 가장 나중에 열린 alert를 3초 유지시킨다.
    return () => clearTimeout(timeout);
  }, []);

  // 가장 최상위 DOM을 선택한다.
  const modalRoot = document.getElementById('modal-root');
  
  // createPortal로 return한다. 
  return createPortal(
    <Backdrop onClick={() => setState(false)}>
      <div onClick={(e) => e.stopPropagation()}>
        {children}
      </div>
    </Backdrop>,
    modalRoot!
  ) as any;
}

4. 소감

  • 처음 스타일 가이드를 잡을때, z-index도 따로 설정에 잡아 놓는 것이 가장 좋겠다.
  • 예를 들어, 항상 최상위에 오는 Backdrop을 최상위, 그 아래로 header, footer 등으로 말이다.
  • 그리고 상수로 z-index를 관리하면 중간에 다른 단계를 넣거나 수정하더라도 편하게 사용할 수 있다.
COMMENT