React에서 Framer Motion 라이브러리로 애니메이션 효과를 적용하던 중 의도치 않은 버그가 발생되었다. 어떻게 버그가 해결되었는지 그리고 왜 이런 버그가 발생했는지 기록하고 정리해보자.

const [direction, setDirection] = useState<'right' | 'left'>('right');
<S.Slider>
<AnimatePresence initial={false} onExitComplete={toggleLeaving}>
<S.SliderControl>
<S.StyledIcon
onClick={() => handleSliderPage(ControlKeys.LEFT)}
icon="chevron-left"
size="3x"
/>
<S.StyledIcon
onClick={() => handleSliderPage(ControlKeys.RIGHT)}
icon="chevron-right"
size="3x"
/>
</S.SliderControl>
<S.Row
variants={rowVariants[direction]}
initial="hidden"
animate="visible"
exit="exit"
transition={{ type: 'tween', duration: 1 }}
key={sliderPage}
>
export const rowVariants = {
left: {
hidden: { x: -window.innerWidth },
visible: { x: 0 },
exit: { x: window.innerWidth },
},
right: {
hidden: { x: window.innerWidth },
visible: { x: 0 },
exit: { x: -window.innerWidth },
},
};
상태를 만들고 이벤트가 일어나면 해당 상태를 애니메이션 속성으로 선택right를 선택left를 선택prop(사용자 정의값)을 전달const [direction, setDirection] = useState<'right' | 'left'>('right');
<S.Slider>
<AnimatePresence
initial={false}
custom={direction}
onExitComplete={toggleLeaving}
>
<S.SliderControl>
<S.StyledIcon
onClick={() => handleSliderPage(ControlKeys.LEFT)}
icon="chevron-left"
size="3x"
/>
<S.StyledIcon
onClick={() => handleSliderPage(ControlKeys.RIGHT)}
icon="chevron-right"
size="3x"
/>
</S.SliderControl>
<S.Row
custom={direction}
variants={rowVariants}
initial="hidden"
animate="visible"
exit="exit"
transition={{ type: 'tween', duration: 1 }}
key={sliderPage}
>
export const rowVariants = {
hidden: (direction: string) => ({
x: direction === 'right' ? window.innerWidth : -window.innerWidth,
}),
visible: { x: 0 },
exit: (direction: string) => ({
x: direction === 'right' ? -window.innerWidth : window.innerWidth,
}),
};

variants prop을 어떻게 사용하는가가 다르다.rowVariants는 direction 값에 따라 다른 객체를 반환한다.S.Row 컴포넌트에서 variants prop은 rowVariants[direction]을 통해 직접 해당 객체를 가져온다.S.Row 컴포넌트가 리렌더링될 때마다 variants prop의 참조(객체)가 변경된다.custom prop을 통해 direction 값을 전달하고 rowVariants가 함수를 통해 값을 계산한다.S.Row 컴포넌트의 variants prop은 rowVariants를 직접 참조하고 있다.S.Row 컴포넌트가 리렌더링되더라도 variants prop의 참조(객체)는 동일하여 추적이 된다.Framer Motion은 내부적으로 애니메이션 상태를
추적하기 위해 참조를 사용한다.
동적으로 애니메이션의 속성을 변경하고자 할때 객체를 할당하면 리렌더링마다 새로운 객체로 참조하게된다.
따라서, 객체의 참조는 일정하게 유지하면서 동적인 값을 주기 위해 custom 속성을 이용한다.