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

Next.js 14中Framer Motion初始加载动画不触发问题求助

Next.js 14 + Framer Motion 初始加载动画不触发的解决方案

针对你遇到的SSR导致初始动画失效、用了'use client'仍无改善的问题,给你几个无需逐个用useEffect触发动画的可行方案:

方案一:添加hydration属性抑制不匹配警告

SSR渲染的静态内容与客户端动画状态可能存在hydration不匹配,导致动画被静默抑制。给motion组件加上hydration={{ suppressHydrationWarning: true }}即可解决:

'use client';
import { motion } from 'framer-motion';

export default function AnimatedComponent() {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ duration: 0.5 }}
      hydration={{ suppressHydrationWarning: true }}
    >
      你的内容
    </motion.div>
  );
}

方案二:用useInView触发视口内动画

如果是元素进入视口才需要动画,利用Framer Motion的useInView钩子,确保仅在客户端检测到元素进入视口时触发动画,天然规避SSR问题:

'use client';
import { motion, useInView } from 'framer-motion';
import { useRef } from 'react';

export default function InViewAnimatedComponent() {
  const ref = useRef(null);
  const isInView = useInView(ref, { once: true }); // 仅触发一次

  return (
    <motion.div
      ref={ref}
      initial={{ opacity: 0, y: 20 }}
      animate={isInView ? { opacity: 1, y: 0 } : {}}
      transition={{ duration: 0.5 }}
    >
      滚动可见时触发动画
    </motion.div>
  );
}

方案三:全局配置MotionConfig统一控制

在根客户端组件(比如app/layout.tsx的客户端部分)用MotionConfig包裹全局内容,统一设置初始动画规则,所有子组件的motion元素会自动继承配置,无需逐个处理:

'use client';
import { MotionConfig } from 'framer-motion';

export default function RootClientLayout({ children }) {
  return (
    <MotionConfig
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      transition={{ default: { duration: 0.5 } }}
    >
      {children}
    </MotionConfig>
  );
}

注意:如果根layout是服务端组件,需要把这个MotionConfig部分拆成独立的客户端组件导入。

方案四:父组件统一控制客户端就绪状态

用单个useEffect在客户端挂载后设置就绪状态,所有子motion组件基于这个状态触发动画,避免逐个写useEffect:

'use client';
import { motion } from 'framer-motion';
import { useState, useEffect } from 'react';

export default function ParentContainer() {
  const [isClientReady, setIsClientReady] = useState(false);

  useEffect(() => {
    setIsClientReady(true);
  }, []);

  return (
    <>
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={isClientReady ? { opacity: 1, y: 0 } : {}}
        transition={{ duration: 0.5 }}
      >
        内容1
      </motion.div>
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={isClientReady ? { opacity: 1, y: 0 } : {}}
        transition={{ duration: 0.5, delay: 0.2 }}
      >
        内容2(延迟动画)
      </motion.div>
    </>
  );
}

补充说明

'use client'只是标记组件为客户端组件,但Next.js 14仍会先在服务端渲染该组件的静态HTML,客户端hydrate时,Framer Motion的初始动画依赖客户端DOM的状态,服务端输出的静态内容没有动画的初始状态,因此需要上述方法来衔接客户端的动画触发逻辑。

内容的提问来源于stack exchange,提问作者lodey

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 19:42:41