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

React中useState存储Axios实例为何变为Promise?如何解决?

问题:React中state里的Axios实例变为Promise的原因及解决方案

原因分析

你遇到的问题核心在于Axios默认导出的实例本身是一个可调用的函数(typeof api === 'function'),而React的useState有特殊规则:如果传入的初始值是函数类型,React会自动执行这个函数,并将其返回值作为初始state。

当你执行const [axios, setAxios] = useState(api)时,React把api(Axios实例)当成了初始化函数,调用api()会返回一个Promise(调用Axios实例本身等同于发起请求,返回Promise),所以state中的axios最终变成了Promise,而非Axios实例本身。

基础问题解决方法

要避免这个问题,你需要用函数式初始化的方式传入初始值,让React执行你提供的箭头函数,返回Axios实例:

import {createContext, useEffect, useState} from "react";
import api from "axios";

export const AxiosContext = createContext({
  axios: null
})

export const AxiosContextProvider = ({ children }) => {
  // 用箭头函数包裹Axios实例,避免被React当作初始化函数执行
  const [axios, setAxios] = useState(() => api);
  
  console.log(api); // 正常Axios实例
  console.log(axios); // 现在也是Axios实例

  return(
    <AxiosContext.Provider value={{ axios }}>
      {children}
    </AxiosContext.Provider>
  )
}

针对授权令牌更新的场景解决方案

结合你需要在登录后动态更新Axios实例请求头的场景,更合理的方案不是替换整个Axios实例,而是直接修改现有实例的默认请求头,或使用请求拦截器动态注入令牌:

方案1:直接修改Axios实例的默认请求头

在用户登录成功后,直接更新现有Axios实例的默认请求头:

// 登录成功后调用
const updateAuthToken = (token) => {
  api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
};

这种方式无需修改state,所有组件使用的都是同一个Axios实例,修改后立即生效。

方案2:使用请求拦截器动态注入令牌

如果令牌可能过期或需实时获取(比如从localStorage读取),推荐使用拦截器:

// 在Axios实例创建后添加拦截器
api.interceptors.request.use(
  (config) => {
    const token = localStorage.getItem('authToken');
    if (token) {
      config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

登录成功后只需将令牌存入localStorage,拦截器会自动在每次请求时注入令牌,无需手动更新实例。

方案3:结合Context和状态管理

如果需要在令牌变化时通知组件重新渲染,可以将令牌存在Context的state中,拦截器从Context读取令牌:

// 在AxiosContextProvider中添加令牌状态
export const AxiosContextProvider = ({ children }) => {
  const [authToken, setAuthToken] = useState(localStorage.getItem('authToken'));
  
  // 登录成功后调用setAuthToken更新令牌
  const login = (token) => {
    localStorage.setItem('authToken', token);
    setAuthToken(token);
  };

  // 创建Axios实例(令牌变化时重新生成)
  const [apiInstance] = useState(() => {
    const instance = api.create();
    instance.interceptors.request.use((config) => {
      if (authToken) {
        config.headers.Authorization = `Bearer ${authToken}`;
      }
      return config;
    });
    return instance;
  }, [authToken]);

  return(
    <AxiosContext.Provider value={{ axios: apiInstance, login }}>
      {children}
    </AxiosContext.Provider>
  )
}

内容的提问来源于stack exchange,提问作者Vinicius Cavalcante Santos

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 18:45:06