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

React useEffect场景下clearTimeout取消定时器不生效问题求助

问题根因

你的代码存在三个核心逻辑漏洞,导致快速切换hover场景下状态异常:

  1. removeCursor 中错误添加了 if (timerRef.current === null) return 判断,定时器执行完成后不会自动重置 timerRef 为 null,部分场景下合法的重置光标逻辑会被意外拦截
  2. 所有定时器执行完成后没有手动重置 timerRef.current 为 null,产生状态残留,干扰后续逻辑判断
  3. 快速跨box移动时,hover状态会先变空触发removeCursor开启500ms定时器,再变回非空触发addCursor,原有逻辑虽然会清定时器,但10ms的延迟设置wait光标容易和残留的重置逻辑产生错位

修正方案

const [hoverItem, setHoverItem] = useState(null)
const timerRef = useRef(null)

const addCursor = useCallback(() => {
  // 先清除所有待执行的定时器,不管是重置光标的还是设置光标的
  clearTimeout(timerRef.current)
  timerRef.current = null
  
  // 没有特殊需求可以直接设置光标,去掉10ms延迟避免状态错位
  document.body.style.cursor = 'wait'

  // 如果必须保留10ms延迟,替换为下面的代码即可
  // timerRef.current = setTimeout(() => {
  //   document.body.style.cursor = 'wait'
  //   timerRef.current = null
  // }, 10)
}, [])

const removeCursor = useCallback(() => {
  // 先清除已有定时器,避免多次触发生成多份异步任务
  clearTimeout(timerRef.current)
  timerRef.current = null

  // 开启500ms延迟重置光标
  timerRef.current = setTimeout(() => {
    document.body.style.cursor = 'default'
    timerRef.current = null
  }, 500)
}, [])

useEffect(() => {
  if (hoverItem) {
    addCursor()
  } else {
    removeCursor()
  }
  // 组件卸载时清除定时器,避免内存泄漏
  return () => clearTimeout(timerRef.current)
}, [hoverItem, addCursor, removeCursor])

逻辑说明

  • 每次触发设置/重置光标逻辑时,都会先清空所有待执行的定时器,保证同一时间只有一个异步任务在队列中
  • 定时器执行完成后主动重置timerRef为null,消除状态残留
  • 移除了冗余的状态判断逻辑,避免合法逻辑被拦截
  • 新增了组件卸载时的定时器清理逻辑,避免内存泄漏

修正后完全满足你的两个需求:

  • 鼠标移出box区域后,光标会保持500ms的wait状态再恢复默认
  • 快速在多个box之间移动时,只要最终停在box上,中间触发的重置光标定时器会被立即清除,始终保持wait光标显示

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 23:09:02