AOS(Animate On Scroll) 라이브러리
// Animate On Scroll
npm install aos
// type script
npm install --save-dev @types/aos
// 예제: AOS를 초기화하는 React 컴포넌트
import { useEffect } from "react";
import AOS from "aos";
import "aos/dist/aos.css";
/**
* AOS 예제 컴포넌트
* 스크롤 시 요소에 애니메이션 효과를 적용합니다.
*
* @returns {JSX.Element} 애니메이션이 적용된 컴포넌트
*/
export default function AOSExample(): JSX.Element {
useEffect(() => {
// AOS 초기화 (애니메이션 지속 시간 1000ms)
AOS.init({ duration: 1000 });
}, []);
return (
<div className="p-8">
<h1 data-aos="fade-up" className="text-2xl font-bold mb-4">
스크롤 애니메이션 예제
</h1>
<p data-aos="fade-left" className="mb-4">
페이지를 스크롤하면 이 문장이 부드럽게 나타납니다.
</p>
<p data-aos="fade-right">
AOS는 매우 간단하게 스크롤 애니메이션을 추가할 수 있도록 도와줍니다.
</p>
</div>
);
}
기타 참고 사항
AOS 라이브러리가 클라이언트에서 DOM 요소에 클래스(예: aos-init, aos-animate)를 추가하면서, 서버에서 렌더링된 HTML과 차이가 발생하기 때문에 나타납니다. 즉, 서버 사이드 렌더링(SSR) 시점에는 해당 클래스가 없는데, 클라이언트에서 AOS 초기화 후 DOM에 추가되면서 hydration mismatch가 발생하는 것입니다.
이 문제를 해결하는 방법은 해당 컴포넌트를 클라이언트 전용으로 렌더링하는 것입니다. 대표적인 두 가지 접근 방식은 다음과 같습니다.
1. 동적 임포트 (Dynamic Import)로 클라이언트 전용 렌더링
Next.js의 동적 임포트를 사용하여 SSR을 비활성화할 수 있습니다. 이렇게 하면 AOSExample 컴포넌트는 클라이언트에서만 렌더링되어 서버와의 HTML 차이가 발생하지 않습니다.
예시:
// 페이지나 부모 컴포넌트에서
import dynamic from "next/dynamic";
// ssr: false 옵션을 추가하여 클라이언트 전용 컴포넌트로 임포트
const AOSExample = dynamic(() => import("../components/AOSExample"), { ssr: false });
export default function HomePage() {
return (
<div>
<h1>홈 페이지</h1>
<AOSExample />
</div>
);
}
이렇게 하면 AOSExample은 서버 사이드 렌더링 없이 클라이언트에서만 렌더링되므로, AOS가 DOM을 수정해도 초기 SSR HTML과 충돌하지 않습니다.
2. 마운트 후 렌더링 (Conditional Rendering After Mount)
컴포넌트 내부에서 useEffect를 사용해 컴포넌트가 클라이언트에서 마운트된 후에만 AOS 관련 로직 및 렌더링을 진행할 수도 있습니다. 예를 들어:
"use client";
import { useEffect, useState } from "react";
import AOS from "aos";
import "aos/dist/aos.css";
/**
* AOSExample 컴포넌트
*
* @returns {JSX.Element | null} AOS 애니메이션 적용 컴포넌트 또는 초기 로딩 시 null
*/
export default function AOSExample(): JSX.Element | null {
const [mounted, setMounted] = useState(false);
useEffect(() => {
// 컴포넌트가 마운트되었음을 표시
setMounted(true);
AOS.init({ duration: 1000 });
}, []);
// 클라이언트에서 마운트 전까지는 아무것도 렌더링하지 않음
if (!mounted) {
return null;
}
return (
<div className="p-8">
<h1 data-aos="fade-up" className="text-2xl font-bold mb-4">
스크롤 애니메이션 예제
</h1>
<p data-aos="fade-left" className="mb-4">
페이지를 스크롤하면 이 문장이 부드럽게 나타납니다.
</p>
<p data-aos="fade-right">
AOS는 매우 간단하게 스크롤 애니메이션을 추가할 수 있도록 도와줍니다.
</p>
</div>
);
}
여기서 mounted 상태는 컴포넌트가 클라이언트에서 마운트된 이후에만 콘텐츠를 렌더링하도록 도와줍니다. 이 경우 SSR 단계에서는 아무 것도 렌더링되지 않으므로, 클라이언트에서 AOS가 적용된 후에 HTML이 일치하게 됩니다.
두 방법 모두 AOS가 클라이언트에서만 동작하도록 하여 hydration mismatch 문제를 해결할 수 있습니다. 프로젝트 상황에 맞게 선택하여 적용해 보세요.