본문 바로가기
Next.js

[Next.js]웹 페이지 전환 효과를 주는 방법들

by goodchuck 2024. 5. 24.

목차

     웹 페이지 전환 효과를 주는 것들은 무엇이 있을까?

    Next.js에서 페이지 전환 효과를 구현하는 방법에는 여러 가지가 있다. 아래는 몇가지 대표적인 방법이다.

     

    Framer Motion

    • Framer Motion은 React 애니메이션 라이브러리로, Next.js에서 페이지 전환 효과를 쉽게 구현할 수 있다.
    • `AnimatePresence`와 `motion.div`를 사용하여 페이지 전환 애니메이션을 적용할 수 있다.
    // components/PageTransition.tsx
    'use client';
    
    import { usePathname } from 'next/navigation';
    import { AnimatePresence, motion } from 'framer-motion';
    import React from 'react';
    
    interface PageTransitionProps {
      children: React.ReactNode;
    }
    
    const PageTransition: React.FC<PageTransitionProps> = ({ children }) => {
      const pathname = usePathname();
    
      return (
        <AnimatePresence mode="wait">
          <motion.div
            key={pathname}
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -20 }}
            transition={{ duration: 0.5 }}
          >
            {children}
          </motion.div>
        </AnimatePresence>
      );
    };
    
    export default PageTransition;
    // app/layout.tsx
    import type { Metadata } from 'next';
    import { Inter } from 'next/font/google';
    import './globals.css';
    import 'prismjs/themes/prism.css';
    import { Flex } from 'antd';
    
    import { HeaderV1 } from '@/containers';
    import RQProvider from '@/app/RQProvider';
    import StoreProvider from './StoreProvider';
    import PageTransition from '@/components/PageTransition';
    
    const inter = Inter({ subsets: ['latin'] });
    
    export const metadata: Metadata = {
      title: 'Create Next App',
      description: 'Generated by create next app',
    };
    
    export default function RootLayout({
      children,
    }: Readonly<{
      children: React.ReactNode;
    }>) {
      return (
        <html lang="en">
          <body className={inter.className}>
            <StoreProvider>
              <RQProvider>
                <Flex gap="middle" style={{ minHeight: '100vh' }}>
                  <HeaderV1 />
                  <PageTransition>{children}</PageTransition>
                </Flex>
              </RQProvider>
            </StoreProvider>
          </body>
        </html>
      );
    }

     

    CSS 애니메이션 사용

    • CSS 애니메이션을 사용하여 페이지 전환 효과를 구현할 수도 있다. 이 방법은 JavaScript 없이 간단한 애니메이션 효과를 적용하는데 유용하다.
    /* styles/globals.css */
    .page-enter {
      opacity: 0;
      transform: translateY(20px);
    }
    
    .page-enter-active {
      opacity: 1;
      transform: translateY(0);
      transition: opacity 0.5s, transform 0.5s;
    }
    
    .page-exit {
      opacity: 1;
      transform: translateY(0);
    }
    
    .page-exit-active {
      opacity: 0;
      transform: translateY(-20px);
      transition: opacity 0.5s, transform 0.5s;
    }
    // pages/_app.tsx
    import { useEffect, useState } from 'react';
    import { useRouter } from 'next/router';
    import '../styles/globals.css';
    
    export default function MyApp({ Component, pageProps }) {
      const [pageTransition, setPageTransition] = useState(false);
      const router = useRouter();
    
      useEffect(() => {
        const handleRouteChangeStart = () => setPageTransition(true);
        const handleRouteChangeComplete = () => setPageTransition(false);
    
        router.events.on('routeChangeStart', handleRouteChangeStart);
        router.events.on('routeChangeComplete', handleRouteChangeComplete);
    
        return () => {
          router.events.off('routeChangeStart', handleRouteChangeStart);
          router.events.off('routeChangeComplete', handleRouteChangeComplete);
        };
      }, [router.events]);
    
      return (
        <div className={pageTransition ? 'page-enter-active' : 'page-exit-active'}>
          <Component {...pageProps} />
        </div>
      );
    }

     

    React Transition Group

    • React Transition Group는 React 애니메이션을 구현하는 또 다른 방법이다. 이 라이브러리는 애니메이션을 위해 상태 기반의 접근 방식을 제공한다.
    // pages/_app.tsx
    import { useEffect } from 'react';
    import { useRouter } from 'next/router';
    import { TransitionGroup, CSSTransition } from 'react-transition-group';
    import '../styles/globals.css';
    
    export default function MyApp({ Component, pageProps }) {
      const router = useRouter();
    
      useEffect(() => {
        const handleRouteChange = () => window.scrollTo(0, 0);
        router.events.on('routeChangeComplete', handleRouteChange);
        return () => {
          router.events.off('routeChangeComplete', handleRouteChange);
        };
      }, [router.events]);
    
      return (
        <TransitionGroup>
          <CSSTransition
            key={router.pathname}
            classNames="page"
            timeout={300}
          >
            <Component {...pageProps} />
          </CSSTransition>
        </TransitionGroup>
      );
    }
    /* styles/globals.css */
    .page-enter {
      opacity: 0;
      transform: translateY(20px);
    }
    
    .page-enter-active {
      opacity: 1;
      transform: translateY(0);
      transition: opacity 0.3s, transform 0.3s;
    }
    
    .page-exit {
      opacity: 1;
      transform: translateY(0);
    }
    
    .page-exit-active {
      opacity: 0;
      transform: translateY(-20px);
      transition: opacity 0.3s, transform 0.3s;
    }

     

    GSAP

    • GSAP(GreenSock Animation Platform)는 매우 강력한 애니메이션 라이브러리이다. GSAP를 사용하여 Next.js 페이지 전환 애니메이션을 구현할 수 있다.
    // pages/_app.tsx
    import { useEffect } from 'react';
    import { useRouter } from 'next/router';
    import gsap from 'gsap';
    
    export default function MyApp({ Component, pageProps }) {
      const router = useRouter();
    
      useEffect(() => {
        const handleRouteChange = (url) => {
          const timeline = gsap.timeline();
          timeline.to('.page', { opacity: 0, duration: 0.5 });
          timeline.to('.page', { opacity: 1, duration: 0.5 });
        };
    
        router.events.on('routeChangeStart', handleRouteChange);
    
        return () => {
          router.events.off('routeChangeStart', handleRouteChange);
        };
      }, [router.events]);
    
      return (
        <div className="page">
          <Component {...pageProps} />
        </div>
      );
    }