按钮触发两次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
相关产品推荐
相关产品推荐

