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

React useState Hook问题:点击按钮无法获取最新state值求助

问题原因

你遇到的是React闭包陷阱:

  • 你的useEffect依赖项是空数组[],所以它只会在组件首次渲染时执行一次。
  • 首次渲染时,c的初始值是0,此时绑定的f1函数会捕获这个c=0的闭包环境。
  • 之后你调用setC(1)更新了状态,组件会重新渲染,生成新的f1函数(此时它能捕获到c=1),但旧的事件监听器还是绑定的首次渲染时的f1,所以点击按钮时输出的还是最初的0。
解决方案

方案1:用React原生的事件绑定(推荐)

完全不用手动操作DOM添加监听器,直接在按钮上通过onClick绑定事件,React会自动帮你处理更新,每次渲染都会绑定最新的f1:

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

export function App(props) {
  const [c, setC] = useState(0);

  useEffect(() => {
    setC(1);
  }, []);

  const f1 = () => {
    console.log(c);
  }

  return (
    <div className='App'>
      <h1>Hello React.</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button onClick={f1} />
    </div>
  );
}

console.log('Hello console')

方案2:手动绑定事件时处理闭包(适合必须操作DOM的场景)

如果一定要手动绑定DOM事件,需要在useEffect中清理旧监听器,并把c加入依赖项,这样c更新时会重新绑定最新的f1:

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

export function App(props) {
  const [c, setC] = useState(0);

  useEffect(() => {
    const button = document.getElementById("b1");
    if (!button) return;
    
    // 绑定最新的f1
    button.addEventListener("click", f1);
    
    // 清理函数:组件卸载或依赖变化时移除旧监听器
    return () => {
      button.removeEventListener("click", f1);
    };
  }, [c]); // 把c加入依赖,c变化时重新执行effect

  useEffect(() => {
    setC(1);
  }, []);

  const f1 = () => {
    console.log(c);
  }

  return (
    <div className='App'>
      <h1>Hello React.</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button id="b1" />
    </div>
  );
}

console.log('Hello console')

方案3:用useRef保存最新状态

如果不想让useEffect依赖c,可以用useRef来保存最新的c值,因为ref的current属性是可变的,闭包能访问到最新值:

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

export function App(props) {
  const [c, setC] = useState(0);
  const cRef = useRef(c);
  
  // 每次c更新时同步到ref
  useEffect(() => {
    cRef.current = c;
  }, [c]);

  useEffect(() => {
    setC(1);
    const b1 = document.getElementById("b1");
    b1.addEventListener("click", f1);
    return () => {
      b1.removeEventListener("click", f1);
    };
  }, []);

  const f1 = () => {
    console.log(cRef.current); // 访问最新的c值
  }

  return (
    <div className='App'>
      <h1>Hello React.</h1>
      <h2>Start editing to see some magic happen!</h2>
      <button id="b1" />
    </div>
  );
}

console.log('Hello console')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:06:48