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

React中useEffect定时器调用函数时count控制台输出异常问题

为什么控制台打印的count始终为0,但页面显示正常递增?

问题代码

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

function Counter() {
  const [count, setCount] = useState(0)

  const incCount = () => {
    console.log("count ", count)

    // setCount(count + 1)
    setCount(x => x + 1)
  }

  useEffect(() => {
    console.log('use effect called')
    const intervalId = setInterval(() => incCount(), 1000)
    return() => {
      // clearInterval(intervalId);
      console.log("clear interval called")
    }
  }, [])

  return (
    <div>
      {count}
    </div>
  )
}

export default Counter

问题描述

页面上的count按预期每秒递增1,但控制台每次仅输出0。incCount函数确实每秒执行一次,控制台打印的count始终为0,与页面显示不符。


原因分析

这是闭包陷阱导致的:

  • 你的useEffect依赖项是空数组[],只会在组件挂载时执行一次。挂载时创建的setInterval回调,引用的是组件第一次渲染时生成的incCount函数。
  • 这个初始版本的incCount捕获了初始状态的count(值为0),之后组件每次重新渲染都会生成新的incCount函数,但定时器里始终用的是旧的那个,所以每次打印的都是初始的0。
  • 而页面显示正常,是因为你用了函数式更新setCount(x => x + 1)——这种方式会直接基于React内部保存的最新状态值计算新状态,不受闭包捕获的旧值影响。

解决方案

方法一:用useRef保存最新状态值

通过useRef同步状态的最新值,让incCount能访问到实时的count:

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

function Counter() {
  const [count, setCount] = useState(0)
  const countRef = useRef(count)

  // 每次count更新时同步ref的current值
  useEffect(() => {
    countRef.current = count
  }, [count])

  const incCount = () => {
    console.log("count ", countRef.current) // 从ref获取最新值
    setCount(x => x + 1)
  }

  useEffect(() => {
    const intervalId = setInterval(() => incCount(), 1000)
    return() => {
      clearInterval(intervalId); // 必须清理定时器,避免内存泄漏
    }
  }, [])

  return (
    <div>
      {count}
    </div>
  )
}

export default Counter

方法二:用useCallback缓存函数并更新依赖

把incCount用useCallback缓存,同时加入useEffect的依赖项,让函数更新时重新创建定时器:

import React, { useState, useEffect, useCallback } from 'react'

function Counter() {
  const [count, setCount] = useState(0)

  // 用useCallback缓存函数,依赖count更新
  const incCount = useCallback(() => {
    console.log("count ", count)
    setCount(x => x + 1)
  }, [count])

  useEffect(() => {
    const intervalId = setInterval(() => incCount(), 1000)
    return() => {
      clearInterval(intervalId); // 清理定时器
    }
  }, [incCount]) // 依赖incCount,函数更新时重新执行useEffect

  return (
    <div>
      {count}
    </div>
  )
}

export default Counter

额外提醒

原代码里注释掉了clearInterval(intervalId),这会导致组件卸载后定时器仍在运行,造成内存泄漏,一定要保留清理逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 05:43:19