I cannot figure out what is going on. I feel like I’m running into a race condition, but I don’t see it. Can anyone lay eyes on this? I’m trying to load a list of "accounts" from an API in useEffect, and use setAccounts()
after it is complete. The API response looks fine in the network tab, but when I try to render from the state variable accounts
I get nada.
Only going to post relevant bits (idToken is from Auth0):
const [accounts, setAccounts] = useState();
const fetchAccounts = async () => {
const url = "http://0.0.0.0:8000/api/v1/account/";
const response = await fetch(url, {
method: "get",
headers: new Headers({
"Content-Type": "application/json",
Authorization: "Bearer " + idToken,
}),
}).then((response) => response.json());
console.log("debug", response);
setAccounts(response);
};
useEffect(() => {
const getToken = async () => {
if (idToken == null) {
const id_token = await getIdTokenClaims();
setIdToken(id_token.__raw);
}
};
getToken();
if (idToken) {
console.log("ID token check", idToken);
fetchAccounts();
getClientPortfolios();
}
console.log("accounts", accounts); //this prints nothing
}, [idToken]);
return (
<div>
{accounts.map((account) => {
<div key={account.id}>{account.name}</div>;
})}
</div>
)
At the moment, all signs point to the state variable not getting set. And the map function throws an error now: Uncaught TypeError: Cannot read properties of undefined (reading 'map')
Is there something weird about how I’m trying to do this?
For reference, here is the debug statement in fetchAccounts:
3
Answers
Oh my goodness. The whole problem was my map function. I had curly braces in there, but no return call. Nothing wrong in my API calls (other than maybe the default state variable should be an empty array)
It needs to be either:
or
You haven’t added the initial state. Always add initial state while using state variables
When you use the State variable before useEffect your return will get rendered. so you will get undefined, and You haven’t checked whether the accounts state has a length > 0 to do a map.
const [accounts, setAccounts] = useState();
-> initializeaccounts
with valueundefined
.useEffect
-> runs after the first render, so you will only get a call tosetAccounts
after the first render.Render uses
accounts
.(1) + (2) + (3) mean the code
accounts.map(...)
runs before yoursetAccounts
call.Solution: check if
accounts
is defined before using it.