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

React页面更新后Canvas动画持续加速问题求助

问题原因

每次页面更新或修改代码后,旧的动画循环未被终止,新的循环又会启动,多个requestAnimationFrame循环同时运行,导致动画速度叠加变快。你的useEffect既没有设置清理逻辑,也未把依赖项(比如r)加入依赖数组,组件更新时旧动画仍在后台运行。

解决步骤
  • 保存requestAnimationFrame的ID,在useEffect的清理函数中用cancelAnimationFrame终止旧循环
  • 将r改为useState变量(修改它时会触发组件更新)
  • 把r加入useEffect的依赖数组,确保r变化时重新初始化动画并清理旧动画
修改后的代码
import React, { useEffect, useRef, useState } from "react";

const CanvasPage = () => {
    const canvasRef = useRef(null);
    const x = useRef(0);
    const [r, setR] = useState(50); // 改为响应式状态
    const v = useRef(1);
    const animationIdRef = useRef(null); // 存储动画ID

    useEffect(() => {
        const canvas = canvasRef.current;
        if (!canvas) return;
        const context = canvas.getContext("2d");

        const render = () => { 
            // 保存当前动画ID
            animationIdRef.current = window.requestAnimationFrame(render);

            x.current = x.current + v.current;
            if(x.current > canvas.width){
                v.current = -1;
            }
            if(x.current <= 0){
                v.current = 1;
            }

            context.clearRect(0, 0, canvas.width, canvas.height);
            context.beginPath();
            context.arc(x.current, 75, r, 0, 2 * Math.PI);
            context.stroke();
        };

        animationIdRef.current = window.requestAnimationFrame(render);

        // 清理函数:组件卸载或依赖变化时终止旧动画
        return () => {
            if (animationIdRef.current) {
                window.cancelAnimationFrame(animationIdRef.current);
            }
        };
    }, [r]); // 加入r作为依赖,r变化时重新执行effect

    return (
        <div className="Canvas">
            <h1>Canvas page</h1>
            {/* 测试用按钮:修改r值验证效果 */}
            <button onClick={() => setR(prev => prev + 10)}>增大半径</button>
            <button onClick={() => setR(prev => prev - 10)}>减小半径</button>
            <canvas id="canvas" ref={canvasRef} height="500px" width="500px" />
        </div>
    )
}

export default CanvasPage;
关键改动说明
  1. animationIdRef:存储每次requestAnimationFrame返回的ID,确保清理时能精准终止对应的动画循环。
  2. 清理函数:useEffect返回的函数会在组件卸载或依赖项变化时执行,用于终止旧动画,避免多循环叠加。
  3. r改为useState:让r成为响应式状态,修改它时触发组件重新渲染,进而触发useEffect的清理与重新初始化。
  4. 依赖数组加入r:确保r变化时,旧动画被清理,新动画使用最新的r值启动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:20:47