如何安全循环framer-motion中useAnimate实现的无限文字轮播动画?
实现framer-motion useAnimate无限文字轮播循环
要让你的文字轮播无限循环,核心是在每次动画序列完成后递归调用动画函数,同时用isMounted控制组件卸载时停止循环,避免内存泄漏。你的代码里已经定义了isMounted但没用到,调整方案如下:
修改后的完整代码
import { useAnimate, cubicBezier } from "framer-motion"; import Image from "next/image"; import highlight from "@/public/highlight.svg"; import { useEffect, useRef } from "react"; const Heading = () => { const [scope, animate] = useAnimate(); const isMounted = useRef(true); const wordsHorizontal = ["Automate", "Enhance", "Streamline", "Automate"]; const wordsVertical = [ "Efficiency", "Productivity", "Performance", "Efficiency", ]; useEffect(() => { const handleAnim = async () => { // 把目标x值整理成数组,循环执行简化代码 const xTargets = [-525, -1050, -1575]; for (const x of xTargets) { if (!isMounted.current) break; // 组件卸载就终止循环 await animate(scope.current, { x }, { duration: 0.6, ease: cubicBezier(0.77,0,0.18,1), delay: 1 }); } if (!isMounted.current) return; // 瞬间重置位置后,递归调用实现无限循环 await animate(scope.current, { x: 0 }, { duration: 0 }); handleAnim(); }; handleAnim(); // 组件卸载时停止循环,防止内存泄漏 return () => { isMounted.current = false; }; }, []); return ( <div className="flex flex-col space-y-8"> <div className="flex space-x-6 items-start"> <div className="relative text-display font-bold w-[525px] h-[120px]"> <div className="absolute inset-0 bg-g-red rounded-3.5xl flex items-center overflow-hidden"> <div ref={scope} className="w-[2100px] flex"> {wordsHorizontal.map((word, index) => ( <div key={index} className="min-w-[525px] rounded-3.5xl flex items-center justify-center" > {word} </div> ))} </div> </div> </div> {/* 补全你原有代码的其他部分 */} </div> </div> ); }; export default Heading;
关键调整说明
- 递归+挂载校验:在动画序列完成并重置位置后,再次调用
handleAnim()实现循环;每次循环前检查isMounted.current,确保组件卸载后立刻终止动画,避免内存泄漏。 - 代码简化:把重复的
animate调用改成遍历数组,减少冗余代码,后续新增轮播项只需修改数组即可。 - 清理逻辑:通过useEffect的返回函数设置
isMounted.current = false,彻底终止组件卸载后的动画执行。
之前你尝试递归可能没加挂载判断,导致组件卸载后动画仍在运行;或是递归时机不对(没等重置动画完成就调用)。调整后即可实现稳定的无限循环效果。
内容的提问来源于stack exchange,提问作者totim_
相关产品推荐
相关产品推荐

