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

React.js实现3D立方体悬停旋转遇最大更新深度超限错误,求方案

React 3D立方体悬停旋转问题排查与优化

错误原因分析

  • 你的useEffect依赖了deg和mouseover两个状态,当mouseover为true时,setDeg(deg+1)会更新deg,触发组件重渲染
  • 重渲染后,useEffect因为deg变化再次执行,又调用setDeg(deg+1),形成无限循环,最终导致React抛出“最大更新深度超限”的警告
  • 另外,else分支里的setDeg(deg)完全多余,deg本身没有变化,强行调用setState会触发不必要的重渲染

更优实现方案

核心思路:用浏览器原生的requestAnimationFrame实现流畅帧动画,通过控制动画的启停来实现悬停旋转、离开停止的效果,彻底避免state循环更新的问题。

优化后的代码示例:

import { useState, useEffect, useRef } from 'react';

function Nav() {
    const [deg, setDeg] = useState(0);
    const [isHovering, setIsHovering] = useState(false);
    // 用ref存储动画帧ID,方便后续取消动画
    const animationRef = useRef(null);

    // 每帧更新立方体角度的逻辑
    const rotateCube = () => {
        // 用函数式更新确保拿到最新的deg值
        setDeg(prevDeg => prevDeg + 1);
        animationRef.current = requestAnimationFrame(rotateCube);
    };

    useEffect(() => {
        if (isHovering) {
            // 鼠标悬停时启动动画
            animationRef.current = requestAnimationFrame(rotateCube);
        } else {
            // 鼠标离开时停止动画
            if (animationRef.current) {
                cancelAnimationFrame(animationRef.current);
            }
        }

        // 组件卸载时清理动画,避免内存泄漏
        return () => {
            if (animationRef.current) {
                cancelAnimationFrame(animationRef.current);
            }
        };
    }, [isHovering]);

    return (
        <div className='container'>
            <button 
                className='btn btn1' 
                onMouseEnter={() => setIsHovering(true)} 
                onMouseLeave={() => setIsHovering(false)}
            > 
                button 
            </button>

            <div className="cube" style={{transform: `rotate3d(0, 1, 0, ${deg}deg)`}}>
                <div className="side front">HIHI</div>
                <div className="side left">sadfasfasdf</div>
                <div className="side right">fffffffffffffffff</div>
                <div className="side back"> sadfjadois fjaisdof</div>
                <div className="side top"> asdfj siodajf iaosd</div>
                <div className="side bottom"> asdfadsi jaosdij f</div>
            </div>

            <button 
                className='btn btn1' 
                onMouseEnter={() => setIsHovering(true)} 
                onMouseLeave={() => setIsHovering(false)}
            > 
                button 
            </button>
        </div>
    );
}

方案优势

  • 借助requestAnimationFrame实现浏览器原生流畅动画,性能远优于频繁更新state的方式
  • 用useRef存储动画ID,精准控制动画启停,不会出现内存泄漏
  • 仅在isHovering状态变化时执行逻辑,彻底避免无限循环问题
  • 函数式更新setDeg(prevDeg => prevDeg + 1)确保每次都能拿到最新的角度值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 20:15:42