라이브러리/framer-motion

[Framer] 프레이머 모션(Framer motion) 상태값 변화없음으로 인한 애니메이션 중단 버그 해결 방법

순코딩 2024. 1. 19. 09:50
// 슬롯텍스트 모션 컴포넌트
const SlotTextMotion = () => {
  // 슬롯에 표시될 문자열을 담은 배열
  const majorArray = [1,2,3,4,5,6,7,8,9,10];

  // 현재 보여지고 있는 슬롯의 인덱스를 나타내는 상태 변수
  const initNum=Math.floor(Math.random() * majorArray.length);
  const [currentIndex, setCurrentIndex] = useState(initNum);
  const [index,setIndex]=useState(1);//

  // 애니메이션이 완료되면  호출되는 함수
  const onAnimationComplete = async () => {
    const randNum = Math.floor(Math.random() * majorArray.length);
    //현재 인덱스(이전에 랜덤으로 뽑은 인덱스)와 현재 뽑은 랜덤 수가 같으면
    //상태(state)변화가 없기 때문에 모션의 key값이 변하지 않고 재렌더링이 이루어지지 않아 애니메이션이 중단된다.
    if(currentIndex===randNum){ 
      await setCurrentIndex(randNum+1);
    }
    // 같지 않을 경우
    else{
      await setCurrentIndex(randNum);
    }
  };

  // Framer motion 애니메이션에 필요한 속성값 객체
  const slotVariants = {
    initial: { rotateX: 0, y: 0, opacity: 1 }, // 초기 상태
    animate: { rotateX: [-90, 0, 90], y: [20, 0, -20], opacity: [0, 1, 0] }, // 위로 올라온다
    transition: { duration: 1.5, ease: "linear", times: [0, 0.5, 1] }, // initial 상태에서 animate 상태까지 도달하는 데에 걸리는 시간은 duration
  };

  return (
    <>
      {/* 애니메이션의 등장,퇴장 감지 / onAnimationComplete을 사용하려면 필요함 */}
      <AnimatePresence>
        {/* 애니메이션 박스 */}
        <motion.div
          key={currentIndex} // 현재 슬롯의 인덱스를 키로 사용하여 애니메이션 처리
          variants={slotVariants}
          initial={slotVariants.initial}
          animate={slotVariants.animate}
          transition={slotVariants.transition}
          // 애니메이션이 완료될 때 호출되는 함수 지정
          onAnimationComplete={onAnimationComplete}
        >
          {/* 슬롯 아이템 보이는 곳 */}
          <SlotText style={{ color: "#72C6EF" }}>{majorArray[currentIndex]}</SlotText>
        </motion.div>
      </AnimatePresence>
    </>
  );
};