문제

해결 과정

1. useModal 분석

2. framer-motion이 문제가 아닐까?

우리는 framer-motion라이브러리로 애니메이션을 넣고 있다.

// Modalwrapper.client.tsx
<motion.div
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  exit={{ opacity: 0 }}
  className="fixed left-1/2 top-0 z-modal h-full w-full max-w-450 -translate-x-1/2 bg-[rgba(0,0,0,0.4)]"
>
  <div ref={modalRef} className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2">
    {children}
  </div>
</motion.div>

여기서, 왜 Modal 아니라 ModalWrapper에 motion을 주는 지 알아야 한다.

Modal에 motion을 넣을 경우, Modal에만 애니메이션이 적용되어 바깥 배경(ModalWrapper)은 애니메이션 없이 먼저 띄어지고 그 후에 Modal만 애니메이션과 함께 천천히 띄어진다.

공식문서를 보면, AnimatePresence는 제거되지 않고 그 안에서 노드가 mount/unmount되어야 한다.

Screenshot 2023-09-04 at 2.07.41 PM.png

Screenshot 2023-09-04 at 2.08.21 PM.png

React tree에서 제거가 될 때 애니메이션을 넣어주는 AnimatePresence를, mount되고 unmount되어지는 ModalWrapper컴포넌트 위에 넣어주어야 한다. ModalWrapper가 mount되고 unmount되어지는 컴포넌트는 ModalProvider이다.

<ModalContext.Provider value={context}>
  {children}
    {Array.from(modalMap.entries()).map(([id, element]) => (
      <React.Fragment key={id}>{element}</React.Fragment>
    ))}
</ModalContext.Provider>

여기서 Modal(엄밀히 말하면 ModalWrapper)가 추가되는 {Array..}를 감싸주면 된다.

<ModalContext.Provider value={context}>
  {children}
  <AnimatePresence>
    {Array.from(modalMap.entries()).map(([id, element]) => (
      <React.Fragment key={id}>{element}</React.Fragment>
    ))}
  </AnimatePresence>
</ModalContext.Provider>