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

React中setInterval的console.log无法反映更新后的状态

React useState闭包陷阱导致setInterval与onClick调用同一函数结果不同

问题代码

"use client"
import React, { useEffect } from 'react'
import { useState } from 'react';
export default function page() {
    const [count, setCount] = useState(0);
    const handleClick = () => {
        setCount((count)=>count + 1);
    };
    function checkVal(){
        console.log(count)
    }
    useEffect(()=>{
        setInterval(checkVal,1000)
    },[])
    return (
    <div>
        <button onClick={handleClick}>{count}</button>
        <button onClick={checkVal}>clickmetocheck</button>
    </div>
  )
}

问题现象

该组件通过两种方式调用checkVal函数输出count值:

  • 通过setInterval定时调用
  • 通过按钮onClick事件触发调用

实际表现存在差异:

  • setInterval调用的checkVal始终打印初始值0,即使点击按钮更新了count
  • 点击按钮触发的checkVal能正确打印更新后的count

原因分析

这是典型的React函数组件闭包陷阱,核心逻辑如下:

  1. 函数组件每次状态更新都会触发重新渲染,每次渲染都会创建全新的函数实例和变量快照。
  2. 组件首次渲染时,count为初始值0,此时定义的checkVal函数会捕获这个0的count变量。
  3. useEffect的依赖数组是空数组,只会在组件挂载时执行一次,里面的setInterval会一直引用首次渲染时的checkVal函数——这个函数里的count永远是首次渲染的快照值0,不会随着后续状态更新而改变。
  4. 而点击按钮触发的checkVal,是组件每次更新后重新创建的新函数实例,它捕获的是当前渲染周期的count快照值,所以能正确输出最新的count。

解决方案

方案一:使用useRef保存最新值

通过useRef保存count的最新值,让checkVal读取ref.current来获取实时状态:

"use client"
import React, { useEffect, useRef } from 'react'
import { useState } from 'react';
export default function page() {
    const [count, setCount] = useState(0);
    const countRef = useRef(count);
    
    // 每次count更新时同步到ref
    useEffect(() => {
        countRef.current = count;
    }, [count]);
    
    const handleClick = () => {
        setCount((count)=>count + 1);
    };
    
    function checkVal(){
        console.log(countRef.current)
    }
    
    useEffect(()=>{
        const timer = setInterval(checkVal,1000)
        return () => clearInterval(timer); // 组件卸载时清理定时器
    },[])
    
    return (
    <div>
        <button onClick={handleClick}>{count}</button>
        <button onClick={checkVal}>clickmetocheck</button>
    </div>
  )
}

方案二:让useEffect依赖count更新定时器

将count加入useEffect的依赖数组,每次count更新时重新创建定时器,确保定时器引用的是最新的checkVal函数:

"use client"
import React, { useEffect } from 'react'
import { useState } from 'react';
export default function page() {
    const [count, setCount] = useState(0);
    const handleClick = () => {
        setCount((count)=>count + 1);
    };
    
    function checkVal(){
        console.log(count)
    }
    
    useEffect(()=>{
        const timer = setInterval(checkVal,1000)
        return () => clearInterval(timer); // 每次更新前清理旧定时器
    },[count])
    
    return (
    <div>
        <button onClick={handleClick}>{count}</button>
        <button onClick={checkVal}>clickmetocheck</button>
    </div>
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:37:19