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 속성을 이용한다.