-
Notifications
You must be signed in to change notification settings - Fork 1
무한 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초로 시간이 줄어들었다.
- 페이지가 렌더링 된 후 스크롤을 최상단으로 올리기
- DOM을 이미지로 저장하기
- Context API에서 불필요한 리렌더링을 줄이는 방법
- 무한 Transition 애니메이션
- Github Action 워크플로우 정의하기
- 무한 Transition 애니메이션 최적화하기
- 무한 Transition 애니메이션 최적화하기 2
- 무한 Transition 애니메이션 최적화하기 3
- fetch timeout 구현하기
- ErrorBoundary 구현하기
- 뒤로가기 confirm 로직 구현하기
- 선착순 밸런스 게임 상태 관리
- Modal 내부 컴포넌트에서 무한 스크롤이 제대로 동작 안되는 문제
- useToggleContents 훅 기본값 설정 및 조건부 사용법
- 폰트 굵기 적용 이슈
- SVG 내부 stroke 속성 값 제어를 위한 SVGIcon Util 함수 및 SVGR 사용 과정
- tailwindCSS의 @apply를 cva로 바꾸기
- 스크롤 내려갈 때 해당 섹션의 요소들 인터렉션 동작
- 공통 컴포넌트 내부에 애니메이션을 넣는 것에 대한 고민
- 특정 컴포넌트 위치에서 헤더 스타일 다르게 적용하는 방법
- 스크롤 거꾸로 올릴 때 IntersectionObserver가 뷰포트 감지 못하는 현상
- 선착순 밸런스 게임 최종 결과 계산에 대한 고민 (08.14)
- 프로그래스바 공통 컴포넌트로 분리
- (08.23 기준) 선착순 서버 시간 연동 문제
- 게임 종료된 상태에서 사용자 게임 참여 여부에 따른 FinalResult 분기 처리
- FinalResult 컴포넌트의 “당신의 선택” 카테고리 설정 이슈
- 게임 접속 시 게임 현재 진행 상태 초기화 및 카운트 다운 설정
- 선착순 밸런스 게임 UX 개선