-
Next.js에서 페이지 전환 애니메이션 구현React 2025. 3. 5. 18:12
웹사이트에서 페이지가 전환될 때, 단순한 화면 변경보다 부드러운 애니메이션이 적용되면
사용자 경험에 있어 긍정적인 영향을 미친다고 생각합니다.
Next.js에서는 기본적으로 페이지 이동 시 애니메이션이 없지만,
이를 직접 구현하여 자연스러운 페이지 전환을 만들 수 있습니다.이번 글에서는 좌우 슬라이드 전환 애니메이션을 적용하는 방법을 공유하겠습니다.
이를 위해 Context API를 활용하여 애니메이션 상태를 관리하고,
커스텀 훅을 만들어 애니메이션을 쉽게 적용할 수 있도록 해보겠습니다.본 예시에서는 Next.js Tailwind CSS를 사용하였습니다.
| Context 생성하기
먼저, 페이지 전환 애니메이션을 관리할 Context를 생성합니다.
이 Context는 애니메이션을 위한 className과 애니메이션 타입(left 또는 right),
그리고 className을 변경하는 함수를 포함하고 있습니다.
"use clinet"; import { createContext } from "react"; export type PageAnimation = "left" | "right"; interface PageTransitionContext { animation: React.RefObject<PageAnimation>; className: string; setClassName: React.Dispatch<React.SetStateAction<string>>; } const PageTransitionContext = createContext<PageTransitionContext | null>(null); export default PageTransitionContext;
여기서 Context의 역할은 다음과 같습니다.
- animation : 현재 적용할 애니메이션 방향 (left 또는 right)
- className : 애니메이션이 적용될 페이지의 클래스
- setClassName : 클래스명을 변경하는 함수
| Provider 생성하기
이제 생성한 Context를 하위 컴포넌트에 공급할 Provider를 만들어줍니다.
이 Provider는 기본적인 페이지 레이아웃(헤더, 푸터 등)을 포함하고,
애니메이션을 관리하는 값을 Context에 설정합니다.
또한, 애니메이션이 적용될 페이지를 children으로 받아 div 박스로 감싸 애니메이션을 적용합니다.
"use client"; import PageTransitionContext, { PageAnimation, } from "@/app/context/page-transition-context"; import cn from "@/utils/cn"; import { useRef, useState } from "react"; import Navbar from "../components/navbar/navbar"; const PageTransitionProvider = ({ className, children, }: React.PropsWithChildren<{ className?: React.ComponentProps<"div">["className"]; }>) => { const [animationClass, setAnimationClass] = useState(""); const animation = useRef<PageAnimation>("left"); return ( <PageTransitionContext.Provider value={{ animation, className: animationClass, setClassName: setAnimationClass, }} > <Navbar /> <div className={cn("relative p-16", className, animationClass)}> {children} </div> </PageTransitionContext.Provider> ); }; export default PageTransitionProvider;
여기서 cn 함수는 tailwind CSS 클래스를 안전하게 합쳐주는 유틸 함수입니다.
이제 Provider를 Next.js의 layout.tsx에서 감싸주면 모든 페이지에서 애니메이션을 사용할 수 있습니다.
<PageTransitionProvider>{children}</PageTransitionProvider>
| 커스텀 훅 만들기
이제 슬라이드 애니메이션을 위한 커스텀 훅을 만들겠습니다.
이 훅은 애니메이션 타입에 따라 Context값을 변경하여 페이지가 적절히 슬라이드 되도록 합니다.
애니메이션 클래스 반환 함수
const getOutAnimation = (animation: PageAnimation) => { return animation === "left" ? "animate-slide-left-out" : "animate-slide-right-out"; }; const getInAnimation = (animation: PageAnimation) => { return animation === "left" ? "animate-slide-left-in" : "animate-slide-right-in"; };
애니메이션 적용 함수
const animate = (animation: PageAnimation, context: PageTransitionContext) => { return new Promise((resolve) => { const className = getOutAnimation(animation); context.setClassName(className); context.animation.current = animation; setTimeout(resolve, SLIDE_ANIMATION_DURATION); }); };
커스텀 훅 완성
const usePageTransition = () => { const pageTransitionContext = useContext(PageTransitionContext); if (!pageTransitionContext) { throw new Error( "usePageTransition은 PageTransitionContext 내부에서 사용해야 합니다." ); } const context = pageTransitionContext; const slideLeft = () => animate("left", context); const slideRight = () => animate("right", context); const slideIn = () => { if (context.animation.current) { const animation = getInAnimation(context.animation.current); context.setClassName(animation); } }; return { slideLeft, slideRight, slideIn }; };
| 애니메이션 적용하기
기본적으로 페이지 전환 기능은 다음과 같이 동작합니다.
- 링크를 클릭하면 애니메이션 className을 붙여서 페이지가 슬라이드 되도록 한다.
- 슬라이드가 완료되면 페이지를 이동시킨다.
- 이동이 완료되면 페이지가 슬라이드 되어 들어오도록 한다.
페이지 입장 시 애니메이션 적용
먼저 페이지에 입장할 때 해당 페이지가 적절히 슬라이드 되어 오도록 초기화해 줘야 합니다.
따라서, 애니메이션이 적용될 페이지에 커스텀 훅에 있는 slideIn 함수를 실행시켜 줍니다.
export default function Home() { const { slideIn } = usePageTransition(); useEffect(() => { slideIn(); }, []); return ( <div> <h1>Main Page</h1> </div> ); }
페이지 이동 시 애니메이션 적용
이제 페이지에서 나갈 때 슬라이드 되어 사라지도록 해야 합니다.
이를 구현하려면 링크를 클릭하면 커스텀 훅에 있는 slideLeft나 slideRight를 사용하여 페이지가 슬라이드 되도록 한 후 해당 애니메이션이 완료되면 Next.js의 useRouter를 사용해 페이지를 이동시켜 줍니다.
링크를 클릭하면 실행될 navigation 함수를 다음과 같이 만들어 줍니다.
// 링크 데이터 const navLink = [ { title: "Home", url: "/" }, { title: "About", url: "/about" }, { title: "Services", url: "/services" }, { title: "Contact", url: "/contact" }, ]; // 함수 const navigation = (url: string) => { if (pathname === url) return; const curIndex = navLink.findIndex((link) => link.url === pathname); const clickIndex = navLink.findIndex((link) => link.url === `${url}`); if (curIndex > clickIndex) { slideRight().then(() => { router.push(url); }); } else { slideLeft().then(() => { router.push(url); }); } };
여기서 usePathname을 활용해 같은 url에서는 동작하지 않게 합니다.
또한, 링크 순서에 따라 적절하게 오른쪽, 왼쪽 애니메이션이 구분되어 작동되도록 하면
더욱 보기 좋은 애니메이션이 구현될 수 있습니다.
| 끝
이제 Next.js에서 페이지 이동 시 자연스러운 슬라이드 애니메이션이 적용되었습니다.
하지만 페이지 이동시 translateX값을 지속적으로 변경하는 방식이므로
브라우저에서 리페인트 비용이 발생할 수 있습니다.
이는 성능적으로 최적화된 솔루션은 아니며,
많은 애니메이션을 동시에 실행할 경우 성능 저하가 발생할 수도 있습니다.
또한, 애니메이션이 사용자 경험을 반드시 향상시키는 것은 아닙니다.
애니메이션이 너무 길거나 불필요하게 추가되면 오히려 사용자의 피로감을 유발할 수도 있습니다.
따라서 페이지 전환 애니메이션을 적용할 때는 사용자 경험을 종합적으로 고려하여
적절한 연출을 선택하는 것이 중요합니다.
'React' 카테고리의 다른 글
[React] useState와 useRef를 통한 상태 관리 (애니메이션 상태 최적화) (0) 2024.12.30 [React] 리액트에서 컴포넌트 추상화에 대한 고민 (0) 2024.09.21 [vite.js / react] yarn berry 사용하기 (vscode 타입스크립트 오류) (0) 2024.07.14 무한 스크롤을 구현하기 위한 몇 가지 방법들 (Intersection Observer API를 사용하는 이유) (1) 2024.06.17 [Next.js] 프로젝트에 PWA 적용하기 (0) 2024.05.28