-
Notifications
You must be signed in to change notification settings - Fork 2
useAnimation Hook
eVe68 edited this page Aug 25, 2024
·
3 revisions
- 다양한 애니메이션과 인터렉션에 대해서 시작, 끝을 함수로 관리해 유동적으로 사용할 수 있도록 하고자 함
- 함수로 애니메이션을 관리하면 애니메이션 테스트 또한 쉽게 가능하다고 생각함
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를 사용하여 애니메이션을 제어
- carRef로 가져온 ref에 애니메이션 적용
- carMoveRight 키프레임 애니메이션을 적용
- FCFSWinOptions을 키프레임 애니메이션 옵션으로 적용
- 타입스크립트 제네릭 타입 적용
- useRef로 설정한 elementRef가 특정 HTML 요소 타입에 정확하게 매핑
- 시작 함수와 시작 옵션, 종료 함수와 종료 옵션 추가
- 시작 함수는 애니메이션 훅을 사용, 종료 옵션은 tailwind CSS 사용
- 종료 옵션이 적용되지 않음
- 같은 opacity를 조작하지만 조작하는 주체가 달라 충돌하는 듯 함
- 애니메이션 훅에 종료 옵션이 필요해짐
- animationRef의 null 검사를 정확하게 하지 않음
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,
};
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 };
};
- 🛠️ 테스트 코드 작성
- 워드 클라우드
- 컴포넌트 설계
- 스토리북 적용
- useAnimation Hook
- 룰렛 컴포넌트
- 토스트 컴포넌트
- useInView Hook
- 색상 영역 컴포넌트
- msw
- webpack
- 컴포넌트 동시에 띄우기