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

React函数组件useState首次点击取值undefined需两次点击问题排查

问题原因

你遇到的首次点击取到undefined、第二次点击才拿到正常值的问题,核心是对React状态更新机制和JS闭包的理解有偏差,具体点:

  • React的状态更新是异步批处理的,调用setGetCode不会立刻修改当前函数作用域内的GetCode常量,只有等组件完成重渲染后,新的渲染周期生成的作用域里,GetCode才是更新后的值
  • 你写的GetCodeMI没有返回Promise实例,在InsertInternalMov里链式调用.then本身就不符合Promise逻辑,就算接口请求完成触发了setGetCode,当前闭包里捕获的还是初始值(空字符串),取[0]自然是undefined
  • 第二次点击能拿到值,是因为第一次点击触发的状态更新已经完成重渲染,第二次点击执行时闭包里捕获的已经是上一次更新后的值了
可直接用的解决方案

方案1:直接返回接口结果(最适合你的场景)

如果只是要在请求完成后立刻拿到返回值做后续逻辑,不需要等状态更新,直接把接口结果从请求函数里return出来就行,状态该存还是存,供页面渲染使用:

const [GetCode, setGetCode] = useState("");

const GetCodeMI = () => {
  // 记得把Promise return出去
  return Axios.get('http://localhost:3001/GetMICode')
    .then((response) => {
      const resData = response.data;
      setGetCode(resData); // 正常存状态,不影响页面渲染
      return resData; // 直接把最新数据返回给调用方
    });
}   

const InsertInternalMov = async () => {
  // 直接拿到接口返回的最新值,不存在闭包旧值问题
  const latestCode = await GetCodeMI();
  console.log(latestCode[0]);
  // 后续业务逻辑直接用latestCode即可
}

方案2:用useEffect监听状态变化

如果你的后续逻辑必须依赖状态变量本身,就把状态变更后要执行的逻辑放到useEffect里,监听对应状态的变化,状态更新完成后自动执行:

import { useState, useEffect } from 'react';

const [GetCode, setGetCode] = useState("");

const GetCodeMI = () => {
  Axios.get('http://localhost:3001/GetMICode')
    .then((response) => {
      setGetCode(response.data);
    });
}   

// 监听GetCode的变化
useEffect(() => {
  // 跳过初始空值的场景
  if (GetCode?.length > 0) {
    console.log(GetCode[0]);
    // 这里写拿到code后要执行的业务逻辑
  }
}, [GetCode]);

const InsertInternalMov = () => {
  GetCodeMI();
  // 不要在这里直接读取GetCode,必然拿到旧值
}
核心机制提醒
  • 用const声明的React状态,在单次渲染的作用域里是永远不变的,setState本质是触发组件重渲染,在新的渲染周期里生成新的常量值,而不是修改当前作用域的已有变量
  • 永远不要在调用setState的同一个同步/异步上下文里,直接读取状态变量期待拿到更新后的值,这不是bug,是React的正常设计
  • 对需要立刻使用的接口返回值,直接用接口返回的原始数据即可,不用绕一圈等状态更新再读,避免无意义的闭包问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 13:48:13