📝 배경
- 탑개미자원 웹 제작 프로젝트를 진행하며, 스크롤을 일정 범위 이상으로 내릴 시 페이지 최상단으로 이동하는 TopButton이라는 컴포넌트가 조건부렌더링 되도록 구현중이었습니다.
- 페이지 최상단으로 이동하는 기능을 구현하는것은 쉬우나, 해당 컴포넌트가 마운트, 언마운트 될 시 애니메이션 효과를 부여하고 싶은 상황이었습니다.
- 해당 프로젝트에의 각종 애니메이션 효과는 Framer Motion이라는 라이브러리를 사용중이었습니다.
🔍️ 문제 상황
- 애니메이션 효과는 그냥 라이브러리를 통해서 구현하면 되는거 아닌가? 라고 생각할수도 있습니다.
- 물론 React나 next.js 에서 컴포넌트는 조건부 렌더링을 통해 쉽게 추가되거나 제거할 수 있죠.
- 하지만, 일반적으로 컴포넌트가 사라질 때 애니메이션을 적용하는 것은 어렵습니다.
- 왜냐하면 컴포넌트가 언마운트되면 즉시 DOM에서 제거되기 때문입니다. 이 때문에 해당 컴포넌트에 연결된 모든 애니메이션도 즉시 중단되어 버리게 됩니다..
- 그럼 어떤식으로 구현을 해야할까요? 아래 예시 코드를 살펴보겠습니다.(react 코드)
import { useState, useEffect } from 'react';
import './MyComponent.css'; // CSS 애니메이션을 정의한 CSS 파일
const MyComponent = () => {
const [visible, setVisible] = useState(true);
useEffect(() => {
return () => {
setVisible(false);
setTimeout(() => {
// 여기서 컴포넌트를 언마운트합니다.
}, 1000); // CSS 애니메이션의 지속 시간과 일치하게 설정
};
}, []);
return (
<div className={`my-component ${visible ? 'enter' : 'exit'}`}>
{/* 컴포넌트 내용 */}
</div>
);
};
// my-component 클래스에는 기본 애니메이션 스타일이, enter 클래스에는 컴포넌트가 마운트될 때 적용할 애니메이션 스타일이, exit 클래스에는 컴포넌트가 언마운트될 때 적용할 애니메이션 스타일이 CSS에서 정의되어 있어야 합니다
- 위와 같이, useState와 useEffect 그리고 useEffect의 콜백함수 안에 setTimeout 함수를 통해 css 애니메이션의 지속시간과 일치하게 설정해줘야 합니다. 다소 번거로운 작업이네요.
- 또한, 위 방법은 컴포넌트가 실제로 언마운트되지 않고, 상태 변경에 의해 애니메이션만 적용되는 것이므로 주의해야 합니다.
🔨 Framer Motion 라이브러리 에서는?
- AnimatePresence
- Framer Motion 라이브러리에서는 AnimatePresence라는 컴포넌트를 제공하고 있습니다.
- AnimatePresence는 위의 예시와 같은 한계? 불편한점을 극복하기 위해 설계되었습니다.
- AnimatePresence 컴포넌트로 감싸진 자식 컴포넌트들은 exit 속성을 통해 언마운트 애니메이션을 정의할 수 있습니다.
- 이 exit 애니메이션은 컴포넌트가 React 트리에서 제거되기 전에 실행되며, 이렇게 하면 컴포넌트가 사라질 때도 애니메이션을 적용할 수 있습니다.
- 따라서 AnimatePresence는 컴포넌트가 마운트되거나 언마운트될 때 애니메이션을 적용하는 데 매우 유용하다고 할 수 있습니다.
- 실제 코드 적용(next.js 14버전)
"use client";
import { useEffect, useState } from "react";
import { BiUpArrow } from "react-icons/bi";
import { motion, AnimatePresence } from "framer-motion";
const TopButton = () => {
const [isScrolling, setIsscrolling] = useState<boolean>(false);
const hoverMotion = {
transition: {
type: "spring",
stiffness: 500,
damping: 15,
},
whileHover: { scale: 1.2 },
};
useEffect(() => {
const handleScroll = () => {
if (window.scrollY > 100) {
setIsscrolling(true);
} else {
setIsscrolling(false);
}
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
// 스크롤 최상단으로 이동하는 핸들러함수
const handleButtonClick = () => {
window.scrollTo({ top: 0, behavior: "smooth" });
};
return (
<AnimatePresence>
{isScrolling && (
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ y: 100, opacity: 0 }}
{...hoverMotion}
className="fixed bottom-7 right-7 z-50 bg-red-500 rounded-full p-3 shadow-2xl"
onClick={handleButtonClick}
>
<BiUpArrow color="white" size={"23px"} />
</motion.div>
)}
</AnimatePresence>
);
};
export default TopButton;
- AnimatePresence 컴포넌트를 이용하여 간단하게 마운트, 언마운트 시 애니메이션 효과를 적용 할 수 있습니다!
'Project > 탑개미자원' 카테고리의 다른 글
[Next 14] Next.js에서 서버리스로 API 라우팅을 구현해보자. (feat. mongoDB) (0) | 2023.12.22 |
---|---|
[Vercel] vercerl에서 한글 도메인을 등록할 수 있을까? (0) | 2023.11.21 |