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

React中useEffect内setTimeout无限运行导致Toast组件无限重渲染如何解决

问题根源

你遇到的无限重渲染是由第二个useEffect的逻辑和状态更新逻辑共同导致的:

  • 你把整个showState对象作为该useEffect的依赖项,只要showState引用变化就会触发effect执行
  • 定时器执行setShowState时传入的是新的对象字面量,哪怕所有属性值和旧状态完全一致,React也会判定为状态更新,触发组件重渲染
  • 重渲染后showState引用变化,再次触发该useEffect,开启新的定时器,2秒后又执行状态更新,形成死循环
解决方案

调整第二个useEffect的逻辑,只有当Toast处于显示状态时才启动隐藏定时器,同时减少不必要的状态更新:

  1. 给effect逻辑加显示状态判断,隐藏状态下不启动定时器
  2. 依赖项只需要showState.top即可,不需要监听整个对象
  3. 状态更新时增加前置判断,已经是隐藏状态就不执行更新,避免无意义的重渲染

修改后的代码如下:

// hide notification after 2 seconds
useEffect(() => {
  // 非显示状态直接返回,不启动定时器
  if (showState.top <= 0) return
  const timerId = setTimeout(() => {
    setShowState(prevState => {
      // 已经是隐藏状态就返回原状态,不触发更新
      if (prevState.top === -100) return prevState
      return {
        top: -100,
        msg: '',
        bgColor: `#ffffff00`,
      }
    })
  }, 2000)

  return () => {
    clearTimeout(timerId)
  }
}, [showState.top])
额外优化建议

如果你希望Toast隐藏后,新的通知到来时能正常触发显示逻辑,可以检查redux返回的create_notification.success_info是否每次返回新的对象引用,若message和code无变化可缓存该对象,避免触发不必要的第一个useEffect执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 01:36:04