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

Next.js中useState未正确更新setState致动画异常问题

解决Next.js中Framer Motion首屏动画仅首次加载的问题

核心问题分析

你碰到的问题大概率是这两个原因:

  1. 组件初始化时没正确从localStorage读取状态,导致useState初始值始终处于动画可播放状态
  2. useEffect的依赖数组设置错误,或是逻辑里同时修改状态和触发依赖,引发无限渲染

修正方案

先看修正后的代码,再逐点解释:

import { motion } from "framer-motion";
import { useState, useEffect } from "react";

export default function Hero() {
  // 初始化状态:默认设为true(首次加载),后续在useEffect里从localStorage修正
  const [showAnimation, setShowAnimation] = useState(true);

  useEffect(() => {
    // 只在客户端执行,避免Next.js SSR时访问localStorage报错
    const hasSeenAnimation = localStorage.getItem("hasSeenHeroAnimation");
    
    if (hasSeenAnimation) {
      // 如果已经看过动画,更新状态为false
      setShowAnimation(false);
    } else {
      // 首次加载:标记已看过动画,然后更新状态防止重复播放
      localStorage.setItem("hasSeenHeroAnimation", "true");
      setShowAnimation(false);
    }
  }, []); // 空依赖数组,确保只在组件挂载时执行一次

  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={showAnimation ? { opacity: 1, y: 0 } : { opacity: 1, y: 0 }}
      transition={{ duration: 0.6 }}
    >
      {/* Hero组件内容 */}
      <h1>欢迎访问我的网站</h1>
    </motion.div>
  );
}

关键细节说明

  • SSR兼容:Next.js服务端渲染时无法访问localStorage,所以不能直接在useState里写localStorage.getItem(...),必须放在useEffect里(useEffect仅在客户端执行)
  • 空依赖数组:useEffect用空依赖确保只在组件首次挂载时执行一次,不会触发无限渲染
  • 状态更新时机:首次加载时先标记localStorage,再更新showAnimation为false,确保动画只播放一次;用户刷新页面时,localStorage已有记录,直接把状态设为false,动画不再触发
  • 结合动画完成事件(可选):如果想确保动画完全播放完再标记,可以用framer-motion的onComplete:
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={showAnimation ? { opacity: 1, y: 0 } : { opacity: 1, y: 0 }}
      transition={{ duration: 0.6 }}
      onComplete={() => {
        if (showAnimation) {
          localStorage.setItem("hasSeenHeroAnimation", "true");
          setShowAnimation(false);
        }
      }}
    >
      {/* 内容 */}
    </motion.div>
    
    这种方式下,useEffect只负责读取localStorage设置初始状态,动画完成后再更新存储和状态,逻辑更严谨。

常见错误排查

  • 如果还是无限渲染:检查是否在useEffect里修改了依赖数组里的变量,比如把showAnimation放进依赖,同时在里面调用setShowAnimation,就会触发循环
  • 如果动画还是一直显示:检查localStorage的键名是否一致(比如存的时候是hasSeenHeroAnimation,读的时候写成hasSeenAnimation),或是初始化状态没被正确覆盖

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:15:12