使用framer-motion库时,变体的Transition duration不生效问题
问题:数据变化后动画无法自动恢复初始状态
期望首次数据变化时,animate状态的动画运行1秒后恢复至initial状态,但实际动画始终保持,未按预期恢复。
相关代码
const variants = { initial: { boxShadow: 'inset 0 0 0px 0 rgba(0,0,0,0)' }, animate: { boxShadow: 'inset 0 0 20px 0 #ffc940', transition: { duration: 1, ease: 'easeInOut', }, }, exit: { boxShadow: 'inset 0 0 0px 0 rgba(0,0,0,0)' }, }; const FlashingTableCell: FC<FlashingTableCellProps> = ({ value, type }) => { const prevValueRef = useRef(value); const [shouldAnimate, setShouldAnimate] = useState(false); useEffect(() => { if (type !== 'button') return; prevValueRef.current !== value ? setShouldAnimate(true) : setShouldAnimate(false); prevValueRef.current = value; }, [value]); return ( <AnimatePresence> <motion.td key={String(value)} variants={variants} initial="initial" animate={shouldAnimate ? 'animate' : 'initial'} > {value} </motion.td> </AnimatePresence> ); };
问题原因
当前代码中,shouldAnimate仅在数据变化时被设为true,但没有任何机制在动画执行完毕后将其重置为false,导致组件一直停留在animate状态。
修复方案
方案一:利用动画完成回调
通过motion组件的onAnimationComplete回调,在动画结束后自动重置状态:
const FlashingTableCell: FC<FlashingTableCellProps> = ({ value, type }) => { const prevValueRef = useRef(value); const [shouldAnimate, setShouldAnimate] = useState(false); useEffect(() => { if (type !== 'button') return; if (prevValueRef.current !== value) { setShouldAnimate(true); } prevValueRef.current = value; }, [value]); return ( <motion.td key={String(value)} variants={variants} initial="initial" animate={shouldAnimate ? 'animate' : 'initial'} onAnimationComplete={() => { if (shouldAnimate) setShouldAnimate(false); }} > {value} </motion.td> ); };
方案二:使用定时器重置状态
在触发动画后,设置一个与动画时长一致的定时器,到期后重置状态(注意清理定时器避免内存泄漏):
const FlashingTableCell: FC<FlashingTableCellProps> = ({ value, type }) => { const prevValueRef = useRef(value); const [shouldAnimate, setShouldAnimate] = useState(false); useEffect(() => { if (type !== 'button') return; let timer: NodeJS.Timeout; if (prevValueRef.current !== value) { setShouldAnimate(true); timer = setTimeout(() => { setShouldAnimate(false); }, 1000); // 与动画duration保持一致 } prevValueRef.current = value; return () => clearTimeout(timer); }, [value]); return ( <motion.td key={String(value)} variants={variants} initial="initial" animate={shouldAnimate ? 'animate' : 'initial'} > {value} </motion.td> ); };
注:原代码中的AnimatePresence组件并未实际用到(没有触发exit动画的场景),可以直接移除,不影响功能。
内容的提问来源于stack exchange,提问作者Lonli-Lokli
相关产品推荐
相关产品推荐

