I have the following React component, it works very weird! Everyhing inside useEffect
hook is correct (console.log shows correct value of the instance), but After calling setApiInstance
with the newly created axios instance, the apiInstance
unexpectedly becomes a Promise object, which is quite unusual!
Codepen: https://codesandbox.io/p/sandbox/4j2dzs?file=%2Fsrc%2FApp.tsx%3A15%2C30
import React, { useEffect, useState } from "react";
import axios, { AxiosInstance } from "axios";
const MyComponent = ({ appConfig }: { appConfig: { host: string } }) => {
const [apiInstance, setApiInstance] = useState<AxiosInstance | null>(null);
useEffect(() => {
const instance = axios.create({
baseURL: appConfig.host,
});
console.log("instance", instance);
setApiInstance(instance);
}, [appConfig]);
console.log("apiInstance", apiInstance);
if (!apiInstance) return;
return null;
};
export default function App() {
return <MyComponent appConfig={{ host: "0.0.0.0" }} />;
}
But If I create the axios instance in useState
initializer method, it works fine!
const [apiInstance, setApiInstance] = useState<AxiosInstance | null>(() => axios.create({
baseURL: appConfig.host,
params: { website_token: appConfig.websiteToken }
}));
Could you help me find out what is going on?
This is because in React, the setState()
function that you get back from useState()
can accept a function which acts as a state setter function, ie:
setState(currState => newState);
In your case, the instance
which axios.create()
returns is a function, so React treats this as a state setter function when you pass it to setApiInstance()
.
You can get around this by using the state setter function and returning your instance:
setApiInstance(() => instance);
however, I would question whether you need to store your instance in state here in the first place. Something like this is typically better stored in a ref, as your UI most likely won't need to utilise/render your instance:
const apiInstanceRef = useRef<AxiosInstance>();
useEffect(() => {
const instance = axios.create({
baseURL: appConfig.host,
});
apiInstanceRef.current = instance;
}, [appConfig]);