skip to Main Content

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: For reference, here is the debug statement in fetchAccounts

3

Answers


  1. Chosen as BEST ANSWER

    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:

       return (
          <div>
              {accounts.map((account) => {
                  return <div key={account.id}>{account.name}</div>;
              })}
          </div>
      )
    

    or

       return (
          <div>
              {accounts.map((account) => (<div key={account.id}>{account.name}</div>))}
          </div>
      )
    

  2. You haven’t added the initial state. Always add initial state while using state variables

    const [accounts,setAccounts] = useState([])
    

    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.

    {
       accounts.length > 0 && accounts.map((account) => {
            return <div key={account.id}>{account.name}</div>;
       })
    }
    
    Login or Signup to reply.
    1. const [accounts, setAccounts] = useState(); -> initialize accounts with value undefined.

    2. useEffect -> runs after the first render, so you will only get a call to setAccounts after the first render.

    3. Render uses accounts.

    (1) + (2) + (3) mean the code accounts.map(...) runs before your setAccounts call.

    Solution: check if accounts is defined before using it.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search