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

React useState Hook值无法传递到其他函数,状态始终为0怎么解决?

问题原因
  • 闭包捕获旧值问题:你点击Go按钮触发countDown时,函数内部的setInterval和checkAnswer会捕获当前渲染周期的count状态值。后续点击按钮更新count触发组件重渲染,生成的是新的函数作用域,已经启动的定时器闭包永远引用的是触发countDown那一刻的count值,如果点击Go时count是0,后续读取的count就永远是0。
  • 拼写错误:
    1. checkAnswer中判断条件用了未定义的resultat,实际定义的常量是result
    2. 按钮的onClick绑定的是小写的countdown,实际函数名是驼峰的countDown,会触发函数未定义报错
  • 普通变量无持久化:cd是普通let变量,组件每次重渲染都会被重置为5,倒计时的数值更新不会在渲染之间持久化。
  • 不必要的DOM操作:React是状态驱动UI,不需要手动调用getElementById修改DOM内容,直接通过状态绑定到JSX即可。
  • 定时器未清理:setInterval没有配置卸载清理逻辑,组件提前卸载时会触发内存泄漏和报错。
修复后的代码
import { useState, useEffect, useRef } from 'react'

const Component = () => {
  const [count, setCount] = useState(0)
  const [cd, setCd] = useState(0)
  const [message, setMessage] = useState('')
  const intervalRef = useRef(null)
  // 用ref存储最新的count值,规避闭包问题
  const countRef = useRef(count)
  const RESULT = 25

  // 同步最新count到ref
  useEffect(() => {
    countRef.current = count
  }, [count])

  const counterHandler = () => {
    setCount(prev => prev + 1)
  }

  const checkAnswer = () => {
    if (countRef.current > RESULT) {
      setMessage('Yess!')
    } else {
      setMessage('Wrong!!')
      setTimeout(() => {
        setMessage('')
      }, 2000)
    }
  }

  const countDown = () => {
    // 先清理之前的定时器,避免重复点击产生多个定时器
    if (intervalRef.current) clearInterval(intervalRef.current)
    setCd(5)
    intervalRef.current = setInterval(() => {
      setCd(prev => {
        if (prev > 0) {
          return prev - 1
        } else {
          clearInterval(intervalRef.current)
          checkAnswer()
          return 0
        }
      })
    }, 1000)
  }

  // 组件卸载时清理定时器,避免内存泄漏
  useEffect(() => {
    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current)
    }
  }, [])

  return (
    <div>
      <h1>{count}</h1>
      <h4>{cd}</h4>
      <button onClick={counterHandler}>Push Me!</button>
      <button id='go-btn' onClick={countDown}>Go</button>
      <h4>{message}</h4>  
    </div>
  )
}
修复说明
  • 用useRef存储最新的count值,ref在组件全生命周期内引用不变,定时器回调里读取countRef.current就能拿到最新的状态值,解决闭包问题
  • 把cd、message都改为useState状态,自动驱动UI更新,移除所有手动DOM操作
  • 统一修正了所有拼写错误
  • 用useRef存储定时器id,增加了重复点击和组件卸载时的定时器清理逻辑,避免内存泄漏

内容的提问来源于stack exchange,提问作者Luciano M.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 17:27:03