모달창 컴포넌트를 만들었고, 나는 이 컴포넌트가 나오고 사라질 때 애니메이션 처리를 주고 싶었다. 코드를 먼저 살펴보도록 하자.
Modal 컴포넌트
// Modal.tsx
function Modal(): JSX.Element {
const { isShowModal } = useModalStore();
const containerClass = `${styles.container} ${
isShowModal ? "" : styles.close
}`;
return (
<div className={containerClass}>
<div className={styles.modalContent}>
<ModalHeader />
// 기타 컴포넌트들
</div>
</div>
);
}
export default Modal;
ModalHeader 컴포넌트
// ModalHeader.tsx
function ModalHeader(): JSX.Element {
const { closeModal } = useModalStore();
return (
<Container>
<div className={styles.inner}>
<ModalHeaderTitle />
<ExitToAppIcon onClick={closeModal} className={styles.exitIcon} />
</div>
</Container>
);
}
export default ModalHeader;
const Container = styled.div`
background-color: #212121;
height: 60px;
`;
Modal SCSS 모듈
// Modal.module.scss
@import "/src/styles/breakpoints";
@import "/src/styles/mixins";
@keyframes slideDown {
from {
transform: translateY(-10%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideUp {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(-10%);
opacity: 0;
}
}
.container {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
animation: slideDown 0.2s ease;
&.close {
animation: slideUp 0.2s ease;
}
.modalContent {
background-color: white;
width: 100%;
height: 100%;
}
}
Zustand store를 이용하여 isShowModal의 상태를 전역적으로 관리하고, 그 상태의 true, false를 삼항연산자로 계산하여 scss파일에서 각각 반대의 애니메이션을 주고 있다.
모달 창을 React와 Zustand를 사용하여 구현하는 과정에서, 모달이 나타날 때는 애니메이션이 잘 적용되지만 사라질 때는 애니메이션 없이 즉시 사라지는 문제가 발생했다. 이는 UX에 부정적인 영향을 끼칠 수 있는 문제이다.
이 문제의 주요 원인은 Zustand의 상태 변경이 애니메이션 시작 전에 발생하여, CSS 애니메이션이 렌더링 되기도 전에 모달 컴포넌트가 사라지게 되는 것이다. 즉, closeModal 함수가 상태를 즉시 변경하기 때문에, 애니메이션에 필요한 시간이 주어지지 않았다.
모달의 닫힘 상태 관리에 타이밍을 추가하는 방식을 선택했다. closeModal 함수 대신, closeWithDelay라는 새로운 함수를 구현하여 모달의 닫힘 애니메이션이 완료된 후에 상태 변경이 이루어지도록 조정했다. 이를 위해 setTimeout을 사용하여 지정된 시간(예: 150ms)이 지난 후에 closeModal을 호출하도록 설정했다.
수정된 Modal컴포넌트
// Modal.tsx
function Modal(): JSX.Element {
const { closeModal } = useModalStore();
const [isClosing, setIsClosing] = useState(false);
// closeWithDelay 함수 (150ms의 딜레이를 준다.)
const closeWithDelay = (): void => {
setIsClosing(true);
setTimeout(() => {
closeModal();
}, 150);
};
// isClosing으로 조건을 교체
const containerClass = `${styles.container} ${isClosing ? styles.close : ""}`;
return (
<div className={containerClass}>
<div className={styles.modalContent}>
<ModalHeader closeWithDelay={closeWithDelay} />
<div className={styles.content}></div>
<Footer />
</div>
</div>
);
}
export default Modal;
수정된 ModalHeader 컴포넌트
interface IProps {
closeWithDelay: () => void;
}
function ModalHeader({ closeWithDelay }: IProps): JSX.Element {
return (
<Container>
<div className={styles.inner}>
<ModalHeaderTitle />
// onClick 속성에 closeWithDelay 전달
<ExitToAppIcon onClick={closeWithDelay} className={styles.exitIcon} />
</div>
</Container>
);
}
export default ModalHeader;
const Container = styled.div`
background-color: #212121;
height: 60px;
`;
이러한 접근 방법을 통해, 모달창이 사라질 때도 부드러운 애니메이션 효과를 성공적으로 구현할 수 있었다. 이 과정은 React와 Zustand를 사용하는 동안 애니메이션과 상태 변경 사이의 타이밍을 조정하는 중요성을 강조한다. 이러한 간단한 기술을 이용하여 UI의 시각적 매력과 UX를 향상시키는 데 크게 기여할 수 있었다.