React中useEffect修改变量后Framer Motion动画未生效问题
问题根因
- Framer Motion的variant配置只会在动画首次触发时读取一次,你当前将yoyo配置写在
circleanimation的showvariant中,后续circle_Check状态更新后,新的yoyo值不会同步到正在运行的动画中,所以会保持初始的无限循环逻辑。 - 组件内直接编写的
setTimeout没有清理逻辑,每次组件重渲染都会生成新的定时器,多次触发状态更新,也可能导致动画逻辑异常。
修复方案
核心修改点如下:
- 将动态变化的transition配置从variant中抽离,直接绑定到
motion.path的transition属性上,状态更新时配置会自动生效 - 把定时器逻辑包裹在
useEffect中,添加清理函数避免重复触发和内存泄漏 - 静态variant不要包含动态变量,避免重复定义导致的动画异常
修复后完整代码
import React, { useState, useEffect } from "react"; import { motion } from "framer-motion"; import { colors } from "./components/Animations"; export const tick_cross_animation = { hidden: { opacity: 0, pathLength: 0, }, show: { opacity: 1, pathLength: 1, transition: { duration: 1.25 }, }, }; // 静态variant,不含动态变量 const circleVariants = { hidden: { opacity: 0, pathLength: 0, translateX: 5, translateY: 5, rotate: -180, }, show: { opacity: 1, pathLength: 1, }, }; const Work = ({ check, setcheck, cross, setcross }) => { const [circle_Check, setcircle_Check] = useState(Infinity); // 定时器逻辑加清理,仅在组件挂载时执行一次 useEffect(() => { const checkTimer = setTimeout(() => { setcheck(true); }, 1250); const crossTimer = setTimeout(() => { setcross(true); }, 3000); // 组件卸载时清理定时器 return () => { clearTimeout(checkTimer); clearTimeout(crossTimer); }; }, [setcheck, setcross]); useEffect(() => { setcircle_Check(check || cross ? 0 : Infinity); }, [check, cross]); return ( <div className="wow" style={{ width: "80%", margin: "auto", height: "20rem", }} > <svg className="progress-icon" viewBox="0 0 200 200"> <motion.path fill="none" strokeWidth="2" stroke={colors.color_circle} d="M 0, 20 a 20, 20 0 1,0 40,0 a 20, 20 0 1,0 -40,0" variants={circleVariants} initial="hidden" animate="show" {/* 动态transition直接绑定circle_Check状态 */} transition={{ duration: 1.5, yoyo: circle_Check, }} /> {check && ( <motion.path fill="none" strokeWidth="2" stroke={colors.color_tick} d="M14,26 L 22,33 L 35,16" variants={tick_cross_animation} initial="hidden" animate="show" /> )} {cross && ( <motion.path fill="none" strokeWidth="2" stroke={colors.color_X} d="M17,17 L33,33 M33,17 L17,33" variants={tick_cross_animation} initial="hidden" animate="show" /> )} </svg> </div> ); }; export default Work;
效果说明
修改后circle_Check状态变更会实时同步到动画的yoyo配置,当check或cross变为true时,yoyo值变为0,环形动画完成当前循环后就会停止,不会再无限循环。
内容的提问来源于stack exchange,提问作者HakunaMatata
相关产品推荐
相关产品推荐

