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

按钮触发两次Axios请求问题求助:状态未更新致请求失败

问题分析与解决方案

我来帮你拆解下这个问题的核心:React的useState状态更新是异步的。你在第一次请求完成后调用了setUseFetchedToken和setUseFetchedCustomerFromToken,但这些状态并不会立刻更新——React会把状态更新加入队列,等当前函数执行完后再批量处理。所以你紧接着发起的第二次请求,用的还是更新前的旧状态值,自然就传错了数据。

下面给你两种最常用的解决方案:


方案一:直接使用请求响应数据(最简洁)

既然第一次请求已经拿到了最新的token和customer,没必要等state更新,直接用响应里的值构造第二次请求的参数就行:

const [useFetchedToken, setUseFetchedToken] = useState();
const [useFetchedCustomerFromToken, setUseFetchedCustomerFromToken] = useState();
// ...

const fetchData = async () => {
  const firstBody= { url, customer };
  const firstHeader = { headers: {
    'Content-Type': 'application/json;charset=UTF-8',
    'Authorization': 'Bearer ' + token
  } };
  const firstUrl = serverUrl + '/api/view/customer'

  try {
    // 发起第一次请求并获取响应
    const firstResponse = await axios.post(firstUrl , firstBody, firstHeader)
    const tokenFromResponse = firstResponse.data.token
    const decodedCustomer = jwt_decode(firstResponse.data).customer // 注意这里要取response.data

    // 更新状态(用于组件渲染)
    setUseFetchedToken(tokenFromResponse)
    setUseFetchedCustomerFromToken(decodedCustomer)

    // 直接用刚拿到的最新值构造第二次请求参数
    const secondBody = { url, customer: decodedCustomer, startDate, endDate };
    const secondHeader = { headers: {
      'Content-Type': 'application/json;charset=UTF-8',
      'Authorization': 'Bearer ' + tokenFromResponse
    } };
    const secondUrl= serverUrl + '/api/view/user/invoices'

    // 发起第二次请求
    const secondResponse = await axios.post(secondUrl, secondBody, secondHeader)
    // 处理第二次请求的结果...
  } catch (error) {
    // 别忘了错误处理!
    console.error('请求出错:', error)
  }
}

这个方案的优势是逻辑连贯,跳过了state异步更新的等待环节,完全依赖请求返回的实时数据,避免了状态不同步的问题。


方案二:用useEffect监听状态变化(适合解耦场景)

如果需要把两次请求的逻辑分开(比如第一次请求可能由多个事件触发,第二次需要自动跟随状态更新),可以用useEffect监听token和customer的变化,当状态更新后再触发第二次请求:

const [useFetchedToken, setUseFetchedToken] = useState();
const [useFetchedCustomerFromToken, setUseFetchedCustomerFromToken] = useState();
// ...

// 第一次请求:获取token和customer
const fetchTokenAndCustomer = async () => {
  const firstBody= { url, customer };
  const firstHeader = { headers: {
    'Content-Type': 'application/json;charset=UTF-8',
    'Authorization': 'Bearer ' + token
  } };
  const firstUrl = serverUrl + '/api/view/customer'

  try {
    const firstResponse = await axios.post(firstUrl , firstBody, firstHeader)
    const tokenFromResponse = firstResponse.data.token
    const decodedCustomer = jwt_decode(firstResponse.data).customer
    setUseFetchedToken(tokenFromResponse)
    setUseFetchedCustomerFromToken(decodedCustomer)
  } catch (error) {
    console.error('获取token失败:', error)
  }
}

// 第二次请求:用最新状态获取发票
const fetchInvoices = async () => {
  // 确保状态有值再发起请求,避免无效调用
  if (!useFetchedToken || !useFetchedCustomerFromToken) return;
  
  const secondBody = { url, customer: useFetchedCustomerFromToken, startDate, endDate };
  const secondHeader = { headers: {
    'Content-Type': 'application/json;charset=UTF-8',
    'Authorization': 'Bearer ' + useFetchedToken
  } };
  const secondUrl= serverUrl + '/api/view/user/invoices'

  try {
    const secondResponse = await axios.post(secondUrl, secondBody, secondHeader)
    // 处理发票数据...
  } catch (error) {
    console.error('获取发票失败:', error)
  }
}

// 监听状态变化,自动触发第二次请求
useEffect(() => {
  fetchInvoices()
}, [useFetchedToken, useFetchedCustomerFromToken])

// 按钮点击时只触发第一次请求
const handleButtonClick = () => {
  fetchTokenAndCustomer()
}

这个方案把两次请求解耦,适合复杂场景,但要注意加判断条件,避免初始状态为空时发起无效请求。


另外提个小细节:你原来的代码里写了const tokenFromResponse = response.data.token,但这里的response应该是myFirstCall(也就是firstResponse),变量名对应错了,这也可能导致报错哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 21:08:09