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

React State更新问题:setInterval定时器内更新state值不正确

问题修复方案

根因分析

你碰到的是React Hooks的闭包陷阱问题:

  • 你给useEffect传入了空依赖数组[],因此useEffect只会在组件首次挂载时执行一次,内部创建的setInterval回调捕获到的role变量永远是首次渲染时的初始值roles[0]
  • 第一次定时器执行时虽然更新了role状态,但回调函数闭包里的role始终是旧的初始值,第二次执行时计算得到的prevRoleIndex永远是0,无法正确匹配当前最新的角色状态,自然就没法正常更新。
  • 额外隐患:你在切换角色前会把role设为随机字符串,后续用findIndex匹配roles数组时,完全可能出现随机字符串和roles中某一项重合的极端情况,导致索引计算完全错误。

修复方案

我们可以用useRef存储当前最新的角色索引,绕开闭包陷阱,同时避免每次匹配索引的性能损耗和异常风险:

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

const roles = ['Web Developer & UX Designer', 'Software Developer / Engineer', 'Blockchain Developer', 'Data Anaylist/ Scientist']

export default function App() {
  const [role, setRole] = useState(roles[0])
  // 用ref存储当前最新的角色索引,不受闭包影响
  const currentRoleIndexRef = useRef(0)

  const sleep = (value) => {
    return new Promise(r => setTimeout(r, value));
  }
  const getRandomString = () => {
    return (Math.random()).toString(36).substring(2);
  }

  useEffect(() => {
    const timer = setInterval(async () => {
      console.log("Timer has started")
      // 直接从ref取最新的索引,不需要再从role反查
      const prevRoleIndex = currentRoleIndexRef.current
      console.log("Previous Role State: " + roles[prevRoleIndex])

      for (let i = 0; i < 10; i++) {
        setRole(getRandomString())
        await sleep(50)
      }

      // 计算下一个索引,超出长度就回到0实现循环
      const nextRoleIndex = (prevRoleIndex + 1) % roles.length
      const newRole = roles[nextRoleIndex]
      // 更新ref里的索引值
      currentRoleIndexRef.current = nextRoleIndex

      console.log("New Role State: " + newRole)
      setRole(newRole)
    }, 3000);
    return () => clearInterval(timer);
  }, []);

  return (
    <div>
      <h1>{role}</h1>
    </div>
  )
}

修复说明

  • 用useRef存储当前角色索引,ref的取值和修改不受闭包影响,每次都能拿到最新值
  • 索引切换用取模运算% roles.length实现循环播放,写法更简洁
  • 不需要再从当前role反查索引,避免了随机字符串匹配错误的问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 11:24:04