You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中useEffect修改变量后Framer Motion动画未生效问题

问题根因
  • Framer Motion的variant配置只会在动画首次触发时读取一次,你当前将yoyo配置写在circleanimation的show variant中,后续circle_Check状态更新后,新的yoyo值不会同步到正在运行的动画中,所以会保持初始的无限循环逻辑。
  • 组件内直接编写的setTimeout没有清理逻辑,每次组件重渲染都会生成新的定时器,多次触发状态更新,也可能导致动画逻辑异常。
修复方案

核心修改点如下:

  1. 将动态变化的transition配置从variant中抽离,直接绑定到motion.path的transition属性上,状态更新时配置会自动生效
  2. 把定时器逻辑包裹在useEffect中,添加清理函数避免重复触发和内存泄漏
  3. 静态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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 20:15:06