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

如何安全循环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_

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 00:47:40