[Next.js] Lottie로 애니메이션 아이콘 구현하기

srchae·2025년 2월 9일
post-thumbnail

🤔 Lottie란?

Lottie는 에어비앤비에서 개발한 JSON 기반의 애니메이션 파일을 의미하며, 이를 통해 간단한 코드로 애니메이션 아이콘을 구현할 수 있다.
다만, 이를 사용하려면 Lottie를 지원하는 라이브러리의 활용 또한 필요하다.

사용 방법

1. @lordicon/react 설치하기

앞서 설명했듯, Lottie 기반의 애니메이션 아이콘을 적용하기 위해서는 이를 지원하는 라이브러리가 필요했고, 필자는 https://lordicon.com/docs/react 를 선택했다.

@lordicon/react 패키지는 Lottie 애니메이션을 손쉽게 활용할 수 있도록 도와주는 React용 라이브러리이다.

JSON 파일을 직접 가져올 수도 있고, lordicon의 CDN 아이콘을 URL로 불러와서 사용할 수도 있다.

우선 사용에 앞서 해당 패키지를 설치한다.

npm install @lordicon/react

2. Lottie(json) 파일 저장하기

필자는 json 파일을 다운받아 임포트 하는 방식을 사용할 것이다.

마음에 드는 아이콘을 선택한 후, Export를 클릭하면


Export 가능한 확장자 옵션이 나오고 여기서 Lottie를 선택하면 파일이 다운로드된다.
다운로드된 파일은 asset과 같은 폴더에 저장하여 사용한다.

Lottie 파일은 lordicon 뿐만 아니라 다른 애니메이션 아이콘을 제공하는 라이브러리에서 다운로드 해도 이와 같다.
필자는 https://animatedicons.co/ 도 추천한다! (무료로 제공되는 아이콘의 종류가 더 무수하다...👍🏻👍🏻)

3. 커스텀 훅 만들기

동적으로 애니메이션 아이콘을 컨트롤하기 위한 이 동작을
재사용하기 위해 Custom hook으로 구현 해놓는다.

"use client";
import { useEffect, useRef } from "react";

import { Player } from "@lordicon/react";

export const useAnimatedIcon = (count: number) => {
  const playerRefs = useRef<(Player | null)[]>(Array(count).fill(null));

  useEffect(() => {
    playerRefs.current?.forEach((player) => player?.play());
  }, []);

  const handleMouseOver = (index: number) => {
    playerRefs.current[index]?.playFromBeginning();
  };

  return {
    playerRefs,
    handleMouseOver,
  };
};
  1. useRef를 사용하여 Player 객체 배열 관리
    ⇒ 여러 개의 아이콘을 개별적으로 제어하기 위해 playerRefs를 배열로 관리
  2. useEffect를 활용한 자동 실행
    ⇒ 컴포넌트가 마운트될 때 모든 Player 아이콘을 자동 재생 (play())
  3. 마우스를 올리면 애니메이션 다시 실행
    playFromBeginning()을 호출하여 아이콘 애니메이션을 처음부터 다시 실행

4. 적용하기

"use client";

import { useState } from "react";

import clock from "@/assets/clock-hover-clock.json";
import setting from "@/assets/settings-cog-hover.json";
import { useAnimatedIcon } from "@/hooks/useAnimatedIcon";
import { Player } from "@lordicon/react";

const menuItems = [
  {
    label: "출/퇴근 등록하기",
    icon: clock,
  },
  { label: "설정하기", icon: setting },
];

export const NavMenuList = () => {
  const [active, setActive] = useState("");
  const { playerRefs, handleMouseOver } = useAnimatedIcon(menuItems.length);

  return (
    <aside className="w-full min-h-full">
      <nav>
        <ul className="space-y-2">
          {menuItems.map((item, index) => (
            <li key={item.label}>
              <button
                onMouseOver={() => handleMouseOver(index)}
                className={`flex items-center  py-2 rounded-lg w-full text-left text-gray-700 hover:bg-gray-100 transition ${
                  active === item.label ? "font-bold text-black" : ""
                }`}
                onClick={() => setActive(item.label)}
              >
                <div className="px-3 gap-2 flex items-center">
                  <Player
                    ref={(el) => {
                      if (el) playerRefs.current[index] = el;
                    }}
                    icon={item.icon}
                    size={30}
                  />
                </div>
                <span>{item.label}</span>
              </button>
            </li>
          ))}
        </ul>
      </nav>
    </aside>
  );
};
  1. icon 필드에 위에 저장한 json을 임포트하여 Lottie 애니메이션을 적용
  2. useAnimatedIcon(menuItems.length)를 사용하여 각 메뉴 아이콘의 애니메이션을 관리하는 로직을 가져온다.
  3. 각 아이콘(Player)을 useRef 배열(playerRefs)에 저장하여 접근할 수 있도록 설정

적용 화면

profile
🐥집요함과 꾸준함🪽

0개의 댓글