React中useState设置axios实例后变为Promise的异常问题求助
你遇到的并不是apiInstance真的变成了Promise对象,而是浏览器控制台对axios实例的显示误解,以及对React渲染流程的误判:
axios实例是thenable对象,但并非Promise
axios.create()同步返回的是AxiosInstance类型的实例,这个实例本身是一个函数,同时实现了then方法(因为它可以直接作为请求调用,比如instance('/api')返回Promise)。部分浏览器控制台会把带有then方法的对象(即thenable)标记为Promise样式显示,但它本质上是axios的实例,拥有defaults、interceptors等axios特有的属性,和真正的Promise完全不同。React 18 Strict Mode的渲染行为
在你的运行环境中(比如默认启用Strict Mode的Codesandbox),React会模拟组件的卸载和重新挂载,导致:- 组件首次渲染时
apiInstance为null - useEffect执行,创建axios实例并更新状态,组件重新渲染,此时
apiInstance是正确的axios实例 - Strict Mode触发组件卸载,状态重置为
null,再次执行useEffect并更新状态
多次console.log输出可能让你混淆了不同渲染周期的状态值,但每次setApiInstance传入的都是正确的axios实例。
- 组件首次渲染时
两种写法的差异
用useState初始化函数创建实例时,实例只会在组件首次初始化时创建一次(即使Strict Mode下也不会重复创建),所以控制台只会输出一次实例,不会出现多次null和实例交替的情况,让你误以为这种写法“正常”,但本质上两种方式创建的实例是完全一致的。
你可以在代码中添加以下日志,确认apiInstance的真实类型:
console.log("apiInstance is axios instance:", !!apiInstance?.defaults); console.log("apiInstance is Promise:", apiInstance instanceof Promise);
运行后会发现,apiInstance确实是axios实例,而非Promise。
如果只是控制台显示的问题,无需修改代码;如果想避免Strict Mode下的重复实例创建,可以在useEffect中添加逻辑,或者使用useRef存储实例(如果不需要触发重新渲染):
const apiInstanceRef = useRef<AxiosInstance | null>(null); useEffect(() => { const instance = axios.create({ baseURL: appConfig.host }); apiInstanceRef.current = instance; // 若需要触发渲染再调用setState setApiInstance(instance); }, [appConfig]);
内容的提问来源于stack exchange,提问作者masoud khanlo

