Skip to content

useAnimation Hook

eVe68 edited this page Aug 25, 2024 · 3 revisions

Issue

  • 다양한 애니메이션과 인터렉션에 대해서 시작, 끝을 함수로 관리해 유동적으로 사용할 수 있도록 하고자 함
  • 함수로 애니메이션을 관리하면 애니메이션 테스트 또한 쉽게 가능하다고 생각함

커스텀 훅

import React, { useRef } from "react";

interface UseAnimationProps {
  startKeyframes: Keyframe[];
  cancelKeyframes: Keyframe[];
  options: KeyframeAnimationOptions;
}

const useAnimation = ({
  startKeyframes,
  cancelKeyframes,
  options,
}: UseAnimationProps) => {
  const elementRef = useRef<HTMLDivElement | null>(null);
  const animationRef = useRef<Animation | null>(null);

  const startAnimation = () => {
    if (elementRef.current) {
      animationRef.current = elementRef.current.animate(
        startKeyframes,
        options,
      );
    }
  };

  const stopAnimation = () => {
    if (animationRef.current && elementRef.current) {
      animationRef.current = elementRef.current.animate(
        cancelKeyframes,
        options,
      );
    }
  };

  return { elementRef, animationRef, startAnimation, stopAnimation };
};

export default useAnimation;
  • elementRef: 애니메이션을 적용할 HTML
    요소에 대한 참조를 저장해 DOM요소에 애니메이션 적용
  • animationRef: 현재 진행 중인 애니메이션 객체를 저장
  • Web Animations API를 사용하여 애니메이션을 제어
  • 사용법

      const { elementRef: carRef, startAnimation: carStartAnimation } =
        useAnimation({
          startKeyframes: carMoveRight,
          startOptions: FCFSWinOptions,
        });
    export const carMoveRight = [
      { transform: "translateX(0px) scaleX(-0.9) scaleY(0.9)" },
      { transform: "translateX(200vw) scaleX(-0.9) scaleY(0.9)" },
    ];
    
    export const FCFSWinOptions = {
      duration: 500,
      fill: "forwards" as FillMode,
    };
    • carRef로 가져온 ref에 애니메이션 적용
    • carMoveRight 키프레임 애니메이션을 적용
    • FCFSWinOptions을 키프레임 애니메이션 옵션으로 적용

    발생한 이슈

    div 이외에는 사용 불가능

    • 타입스크립트 제네릭 타입 적용
    • useRef로 설정한 elementRef가 특정 HTML 요소 타입에 정확하게 매핑

    이벤트 시작과 종료 함수는 따로 있지만 옵션은 따로 적용 불가능

    • 시작 함수와 시작 옵션, 종료 함수와 종료 옵션 추가
    • 시작 함수는 애니메이션 훅을 사용, 종료 옵션은 tailwind CSS 사용
      • 종료 옵션이 적용되지 않음
      • 같은 opacity를 조작하지만 조작하는 주체가 달라 충돌하는 듯 함
      • 애니메이션 훅에 종료 옵션이 필요해짐

    animationRef에서 에러

    • animationRef의 null 검사를 정확하게 하지 않음

    수정된 useAnimation Hook

    const useAnimation = <T extends Element>({
      startKeyframes,
      cancelKeyframes = [],
      afterStartKeyframes = [],
      startOptions,
      cancelOptions,
      afterStartOptions,
    }: UseAnimationProps) => {
      const elementRef = useRef<T | null>(null);
      const animationRef = useRef<Animation | null>(null);
    
      const startAnimation = async () => {
        const element = elementRef.current;
        if (!element) return;
        animationRef.current = element.animate(startKeyframes, startOptions);
    
        if (afterStartKeyframes.length > 0 && animationRef.current) {
          await animationRef.current.finished;
          element.animate(afterStartKeyframes, afterStartOptions);
        }
      };
    
      const stopAnimation = () => {
        const element = elementRef.current;
        const animation = animationRef.current;
        if (!element || !animation) return;
    
        animationRef.current = element.animate(
          cancelKeyframes,
          cancelOptions ?? startOptions,
        );
      };
    
      return { elementRef, animationRef, startAnimation, stopAnimation };
    };
Clone this wiki locally