skip to Main Content

I have a simple useEffect in my component to fetch data from 3 API calls:

  useEffect(() => {
    Promise.all([
      fetch(`${baseUrl}/counts?entity=color`),
      fetch(`${baseUrl}/counts?entity=brand`),
      fetch(`${baseUrl}/counts?entity=category`)
    ]).then(([x, y, z])=> {
        console.log(x.json(), y.json(), z.json());
      });
  }, []);

I’m expecting the actual data I get from the API so that I can use it in my UI, but instead I’m getting this:
enter image description here

I’ve also tried doing this:

  useEffect(() => {
    Promise.all([
      fetch(`${baseUrl}/counts?entity=color`),
      fetch(`${baseUrl}/counts?entity=brand`),
      fetch(`${baseUrl}/counts?entity=category`)
    ]).then(responses => responses.map(r => r.json()))
      .then(([x, y, z])=> {
        console.log(x, y, z);
      });
  }, []);

I see the desired value inside PromiseResult, but I’m not sure how to extract it:
enter image description here

What am I doing wrong here. How do I access the array in my code?

4

Answers


  1. The issue is that .json returns another promise, so you’d need to call .then on it to get the eventual value. Or since you’re doing multiple, you’d need to combine it with Promise.all, and then call .then on that.

    One possibility is to tweak your .map attempt so that it has an additional Promise.all:

    Promise.all([
      fetch(`${baseUrl}/counts?entity=color`),
      fetch(`${baseUrl}/counts?entity=brand`),
      fetch(`${baseUrl}/counts?entity=category`)
    ]).then(responses => {
      return Promise.all(responses.map(r => r.json()))
    })
    .then(([x, y, z])=> {
      console.log(x, y, z);
    });
    

    But that does have the downside that all of the fetches must get far enough along that they resolve, before any of them can call .json. This may slightly delay finishing things. So another possibility is to set up all of the work up front, and only call Promise.all with those final promises.

    Promise.all([
      fetch(`${baseUrl}/counts?entity=color`).then(val => val.json()),
      fetch(`${baseUrl}/counts?entity=brand`).then(val => val.json()),
      fetch(`${baseUrl}/counts?entity=category`.then(val => val.json()))
    ]).then(([x, y, z])=> {
      console.log(x, y, z);
    });
    

    With that version, each of the fetches will go at whatever pace it can manage, and will convert itself to json as soon as it can. Then once all of them are finished, the combined promise resolves.

    Login or Signup to reply.
  2. If you want to use await instead of then, this is how I would refactor your code:

    useEffect(async () =>
      console.log(...await Promise.all(
        ['color','brand','category']
          .map(async i => (await fetch(`${baseUrl}/counts?entity=${i}`)).json())))
    , []);
    
    Login or Signup to reply.
  3. You could combine your all fetch call and map() to generate an array of promises to easily loop the data:

    const baseUrl = "https://jsonplaceholder.typicode.com";
    
      useEffect(() => {
        const urls = [`${baseUrl}/todos/1`, `${baseUrl}/todos/2`, `${baseUrl}/todos/3`];
    
        const fetchData = async () => {
          try {
            const responses = await Promise.all(urls.map(url => fetch(url)));
            const data = await Promise.all(responses.map(response => response.json()));
            console.log(data);
          } catch (error) {
            console.error(error);
          }
        };
    
        fetchData();
      }, []);
    
    Login or Signup to reply.
  4. Write a getByEntity function that wraps a single fetch operation, then mao over the list of entities that you need to retrieve:

    const baseUrl = '...';
    
    // outside of your component
    async function getByEntity(entity) {
      const response = await fetch(`${baseUrl}/counts?entity=${entity}`);
      const data = await response.json();
      return data;
    }
    
    // inside your component
    useEffect(() => {
      Promise.all(
        ['color', 'brand', 'category'].map(getByEntity)
      ).then(([x, y, z])=> {
        console.log(x, y, z);
      });
    }, []);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search