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

如何在React中用requestAnimationFrame替代setTimeout和clearTimeout

用requestAnimationFrame替换setTimeout实现复制状态重置

首先修正原代码里的一个小问题:原点击事件回调里返回的清理函数不会被自动执行,因为这不是useEffect的清理逻辑。下面是用requestAnimationFrame替换后的完整实现,同时修复了内存泄漏和属性判断错误:

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

const MyComponent = () => {
  const [copyText, setCopyText] = useState("Copy");
  const rafIdRef = useRef(null);

  const copyTextHandler = () => {
    setCopyText("Copied");
    
    // 记录状态切换的开始时间
    const startTime = Date.now();
    const delayDuration = 3000; // 3秒延迟

    const checkAndResetText = () => {
      const elapsed = Date.now() - startTime;
      if (elapsed >= delayDuration) {
        // 时间到,重置文本
        setCopyText("Copy");
        rafIdRef.current = null;
      } else {
        // 未到时间,继续请求下一帧检查
        rafIdRef.current = requestAnimationFrame(checkAndResetText);
      }
    };

    // 启动帧循环
    rafIdRef.current = requestAnimationFrame(checkAndResetText);
  };

  // 组件卸载时清理未完成的requestAnimationFrame
  useEffect(() => {
    return () => {
      if (rafIdRef.current) {
        cancelAnimationFrame(rafIdRef.current);
      }
    };
  }, []);

  return (
    <button 
      onClick={copyTextHandler} 
      disabled={copyText === "Copied"}
    >
      {copyText}
    </button>
  );
};

关键说明:

  • 用useRef存储requestAnimationFrame的ID,这样能在组件的整个生命周期内访问到它,方便后续取消
  • 通过Date.now()计算时间差来模拟3秒延迟,因为requestAnimationFrame本身是按浏览器渲染帧触发(通常60帧/秒),不是直接设置延迟时间
  • 添加useEffect的清理函数,确保组件卸载时如果状态重置还没完成,会取消掉帧请求,避免内存泄漏
  • 修正了原代码中disabled属性的错误判断:原代码误将事件处理函数和字符串比较,现在改为正确的状态值判断

requestAnimationFrame的优势是它的执行时机和浏览器渲染周期同步,不会在页面处于后台时频繁触发(部分浏览器会暂停后台标签的帧请求),相比setTimeout更适合和UI状态同步的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 17:52:41