如何在Framer Motion中实现无卡顿的条件式动画循环?
问题原因
你的代码出现卡顿和无限循环的核心问题是:idleAnimation函数在定义时捕获了isOpen的初始值(false),React状态更新是异步的,且函数内部的变量不会同步更新状态变化。当你点击元素设置isOpen=true后,函数里的isOpen依然是旧的false值,导致while循环无法终止,持续执行动画和console.log,占用主线程造成页面冻结。
解决方案
推荐使用Framer Motion内置的动画序列和重复配置,这是更高效且符合框架设计的实现方式,无需手动维护while循环:
import { useState } from 'react'; import { motion } from 'framer-motion'; const YourComponent = () => { const [isOpen, setIsOpen] = useState(false); // 定义完整的空闲动画序列 const idleVariants = { idle: [ { scaleY: [1, 0.75, 1.1], transition: { duration: 0.5, ease: "easeIn", delay: 1 } }, { y: [0, -75, 0], transition: { ease: "easeInOut", duration: 1, y: { duration: 0.85 } } }, { scaleY: [1.1, 0.95, 1], transition: { duration: 0.5, ease: "easeOut" } } ] }; return ( <motion.div // 根据isOpen状态控制动画播放 animate={isOpen ? "none" : "idle"} variants={idleVariants} // 设置动画无限重复 transition={{ repeat: Infinity }} style={{ originY: "100%" }} onClick={() => setIsOpen(true)} className="Gift" > {/* 组件内容 */} </motion.div> ); }; export default YourComponent;
如果坚持使用useAnimation手动控制,需要用useRef跟踪最新的isOpen状态,避免闭包捕获旧值:
import { useState, useEffect, useRef } from 'react'; import { motion, useAnimation } from 'framer-motion'; const YourComponent = () => { const [isOpen, setIsOpen] = useState(false); const controls = useAnimation(); // 用ref同步最新的isOpen状态 const isOpenRef = useRef(isOpen); useEffect(() => { isOpenRef.current = isOpen; }, [isOpen]); const idleAnimation = async () => { // 通过ref的current判断状态,确保拿到最新值 while (!isOpenRef.current) { await controls.start({ scaleY: [1, 0.75, 1.1], transition: { duration: 0.5, ease: "easeIn", delay: 1 } }); await controls.start({ y: [0, -75, 0], transition: { ease: "easeInOut", duration: 1, y: { duration: 0.85 } } }); await controls.start({ scaleY: [1.1, 0.95, 1], transition: { duration: 0.5, ease: "easeOut" } }); } }; // 组件挂载时启动动画 useEffect(() => { idleAnimation(); }, []); return ( <motion.div animate={isOpen ? null : controls} style={{ originY: "100%" }} onClick={() => setIsOpen(true)} className="Gift" > {/* 组件内容 */} </motion.div> ); }; export default YourComponent;
方案对比
- 内置序列方案:无需手动管理异步循环,Framer Motion会优化动画执行,性能更稳定,代码更简洁。
- useAnimation+useRef方案:适合需要更精细控制动画流程的场景,但需要额外维护ref同步状态,代码复杂度稍高。
内容的提问来源于stack exchange,提问作者user22362540
相关产品推荐
相关产品推荐

