ReactJs中useEffect内调用API出现异步顺序异常及返回值undefined问题
问题根因
- 调用逻辑未加等待控制:
useEffect中直接调用api1、api2两个异步函数时没有加await,async函数执行到内部await语句时会立即返回pending状态的Promise,主线程不会阻塞就会直接执行下一行的api2(),自然就出现了api1没走完就触发api2的情况。 - axios参数配置错误:
axios.put/axios.post的第四个参数不生效,withCredentials属于请求配置项,必须放在第三个参数的config对象中,配置错误可能导致请求鉴权失败、跨域拦截,触发静默报错,最终返回结果为undefined。 - 异步写法混用导致逻辑不可控:同时使用
await和.then链式调用,虽然语法上没有报错,但没有显式返回请求结果,如果你在外部接收api1的返回值自然只能拿到undefined。 - 全局属性覆盖问题:直接修改
axios.myHashData这个全局属性,两个异步请求并行执行时会互相覆盖这个值,可能导致其中一个请求的签名校验失败,返回异常。
修复方案
场景1:需要api1执行完成后再调用api2(串行执行)
useEffect(() => { // 自执行async函数处理异步逻辑 (async () => { await api1(); await api2(); })(); }, []); const api1 = async () => { try { const requestModel = JSON.stringify({ UserId: userid, MenuName: menuname }); const requestBody = security.encrypt(requestModel); // 单独存储签名,不要直接修改axios全局属性,避免并行请求互相覆盖 const hashData = security.computedHmac256(requestBody); const config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', // 签名可放到自定义请求头中,按需替换成你们约定的头字段即可 'X-Hash-Data': hashData }, // withCredentials统一放到config配置项中 withCredentials: true } // 去掉冗余的.then,直接用await拿响应结果 const response = await axios.put(axios.controllername + 'methodname', requestBody, config); if (response.status === 200) { //setapidata(response.data); // 需要返回结果就显式return return response.data; } } catch (error) { console.error('api1请求错误:', error); } } const api2 = async () => { try { const requestModel = JSON.stringify({ UserID: userid }); const requestBody = security.encrypt(requestModel); const hashData = security.computedHmac256(requestBody); const config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'X-Hash-Data': hashData }, withCredentials: true } const response = await axios.post(axios.controllername + 'methodname', requestBody, config); if (response.status === 200) { setapidata(response.data); GetApis(); return response.data; } } catch (error) { console.error('api2请求错误:', error); } }
场景2:两个接口互不依赖,可并行执行,需等待所有请求完成后再处理后续逻辑
替换useEffect内的逻辑即可:
useEffect(() => { (async () => { const [api1Res, api2Res] = await Promise.all([api1(), api2()]); // 后续统一处理两个接口的返回结果 })(); }, []);
如果业务要求必须把签名挂载到axios实例上,不要直接修改全局axios,建议给每个请求单独创建axios实例,避免多个请求互相覆盖配置。
内容的提问来源于stack exchange,提问作者Sarthak parab
相关产品推荐
相关产品推荐

