Skip to content

무한 Transition 애니메이션 최적화하기

juhyojeong edited this page Aug 7, 2024 · 2 revisions

❓ 무한 Transition 애니메이션에서 발생한 문제

캐스퍼 봇 카드 무한 Transition 애니메이션을 구현했는데, 몇 가지 UX적으로 안좋은 점들이 보였다.

애니메이션 시 불필요한 리렌더링 발생으로 버벅이는 문제

2024-08-05.4.35.24.mov

카드에 hover가 될 때마다 카드에 flip 애니메이션이 발생해야하는데, 이때 관련 없는 다른 컴포넌트들에도 리렌더링이 발생하면서 flip 애니메이션이 버벅이는 현상이 있었다.

문제는 리스트를 뿌려주는 컴포넌트에서 hover 된 시점의 x를 저장하고 업데이트 하는 로직을 담당하고 있는데, 그렇다 보니 hover 될 때마다 상태가 바뀌게 되었고, 자식 컴포넌트인 CasperFlipCard 컴포넌트의 리렌더링도 발생한 것이다.

function CasperFlipCard({ size, card, isFlipped }: CasperFlipCardProps) {
  ...
}

export default memo(CasperFlipCard);

react에서 제공하는 memo를 사용해서 props가 변할 때만 리렌더링이 발생하게 수정했다.

2024-08-05.4.35.42.mov

초기 렌더링 시 너무 많은 시간이 걸리는 문제

2024-08-05.5.47.03.mov

showcase 화면으로 넘어갈때 시간이 너무 많이 걸리는 문제가 있었다. 살펴보니 컴포넌트 목록이 100개가 되면서 한 번에 너무 많은 컴포넌트를 렌더링하면서 생기는 문제였다.

navigate 버튼 클릭 1722847626460
showcase load 완료 1722847627011
=> 551

시간을 계산해보니 약 0.6 초가 걸렸다.

문제를 해결하기 위해서 처음에 모든 컴포넌트를 렌더링하지 않고 화면에 보일 때만 렌더링 하게 하기 위해서 IntersectionObserver를 활용했다. viewport와 DOM의 변화를 감지해서 DOM이 보여야하는 위치에 다다랐을 때 렌더링을 할 수 있도록 해줬다.

import { useEffect, useRef, useState } from "react";

export default function useLazyLoading<T extends HTMLElement>() {
    const [isInView, setIsInView] = useState<boolean>(false);
    const cardRef = useRef<T>(null);

    useEffect(() => {
        const observer = new IntersectionObserver(
            ([entry]) => {
                if (entry.isIntersecting) {
                    setIsInView(true);
                    observer.disconnect();
                }
            },
            { threshold: 0, root: document.body }
        );

        if (cardRef.current) {
            observer.observe(cardRef.current);
        }

        return () => {
            if (cardRef.current) {
                observer.unobserve(cardRef.current);
            }
        };
    }, [cardRef]);

    return { isInView, cardRef };
}

위와 같이 card ref를 받아서 해당 카드가 화면에 나와야하는 경우(isIntersecting: true) isInView를 true로 바꿔줘서 카드를 렌더링할 수 있게 해준다.

2024-08-05.5.46.28.mov
navigate 버튼 클릭 1722847591698
showcase load 완료 1722847591728
=> 30

초기 로딩 시간이 0.03초로 시간이 줄어들었다.

📚 학습 정리

🗂️ 멘토링

Clone this wiki locally