Help with axios and async

Hey everyone!

So ihave this functions that fetches some data from an API, here it is:

export const fetchCards = async () => {
  let cards = axios({
    method: "get",
    url: "https://api.pokemontcg.io/v2/cards?page=1&pageSize=10",
    headers: {
      "X-Api-Key": "api key"
    }
  })
    .then((response) => {
      return response.data;
    })
    .catch((error) => {
      console.log(error);
    });

  let result = await cards;

  return result;
};

On page load I want the data it returns to be set as state so I do this:

useEffect(() => {
      setCards(fetchCards());
      setIsLoaded(true);
  }, []);

If I try to access the state, it comes back undefined. It works if I do the following:

useEffect(() => {
    fetchCards().then((data) => {
      setCards(data);
      setIsLoaded(true);
    });
  }, []);

But I do not understand why my state in the first example is set to a Promise. I’m new to get requests and async functions, so I would really appreciate it if someone could help me out here.

let result = await cards;

This line is not doing what you want it to do. I believe you can only use await this way inside of a JS module. So your function is returning before the axios promise is resolved (it’s as if await is not there at all) and the value of cards at that time is a pending promise.

Regardless, I think you are much better off taking full advantage of async/await and rewriting this to get rid of the next and catch blocks.

There was another post about this recently with the same problem on a mongoose query. The problem is you are mixing await/async and promise resolution with .then()/.catch(), so just pick one. Your working example works for that reason; you picked the promise method. If you prefer async/await, then just do it all that way.

This is a common problem; a fairly common solution is outlined here (this is an async/await version). I routinely use variations of this solution to fetch data in react projects.

I’m going to put this here as an example because I think I can basically write these in my sleep at this point in time, and it’s IMO a good example of why hooks are very useful. I think it’s fairly self-explanatory, though useCallback may not be: I’m using it instead of useEffect so I can return a fetch method from the hook.

// api-hooks.js
import { useState, useCallback } from "react";

const headers = { "X-Api-Key": "4d6e33b2-b46f-4b28-814d-786e33f19bc1" };

export function useFetchPokemonCards () {
  const [cards, setCards] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [errorMessage, setErrorMessage] = useState(null);

  const fetchCards = useCallback(async (page = 1, results = 10) => {
    const url = `https://api.pokemontcg.io/v2/cards?page=${page}&pageSize=${results}`;

    setIsLoading(true);
    setErrorMessage(null);
    try {
      const response = await axios.get(url, { headers });
      if (!response.data) {
        setCards([]);
        throw new Error("No results returned!");
      }
      setCards(response.data);
    } catch (err) {
      setErrorMessage(err.message);
    } finally {
      setIsLoading(false);
    }
  }, [cards, errorMessage, page, results]);

  return {
    cards,
    errorMessage,
    fetchCards,
    isLoading,
  }
};
// my-component.js
import { useFetchPokemonCards } from "./api-hooks";

const MyComponent = () => {
  const { cards, errorMessage, fetchCards, isLoading } = useFetchPokemonCards();

  return (
    <section>
      <h2>Fetch some cards!</h2>
      { errorMessage && <p>Oh, no something went wrong! Error message is: {errorMessage}</p> }
      { cards.map((card) => <p key="card.id">Print some info about the card</p>) }
      <button onClick={ fetchCards }>Fetch page 1 from the API</button>
    </section>
  );
};
2 Likes

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.