skip to Main Content

I have an async method called getInitialData to fetch all necessary data from an API. Once the data is fetched, I am passing the data into a table. But by the time the data has been fetched, the data is already passed into the table without having all the necessary data, specifically the second api call to fetch the userItemName. Is there a way to wait for all the data to be fetched first before displaying it?

Here’s how I fetch data using the API

 const getInitialData = async () => {
      const username = user.username;
      await axios
        .get(`http://localhost:8080/api/sellers/${username}/someData`)
        .then((response) => {
          for (const key in response) {
            if (key === "data") {
              response[key].forEach(async (item) => {
                item.name = await getUserItemName(username, item.id);
              });
            }
          }
          setTableData(response.data);
        }); 
    };

useEffect(() => {
        getInitialData();
    }, []);

This is my second API to fetch further data from the database, called in the first API fetch

async function getUserItemName(username, id) {
        const response = await axios.get(
          `http://localhost:8080/api/sellers/${username}/items/${id}`
        );

        return response.data.name;
      }

Here’s my table component

{tableData && <SortingTable ref={sortingTableRef} columns={TABLE_COLUMNS} data={tableData }/>}

3

Answers


  1. You can use to fetch the data with for await

    Login or Signup to reply.
  2. Here’s how you can achieve your desired result, the issue is you can not use forEach with await

    const getInitialData = async () => {
      const username = user.username;
      await axios
        .get(`http://localhost:8080/api/sellers/${username}/someData`)
        .then((response) => {
          for (const key in response) {
            if (key === "data") {
              for (let i = 0; i < response[key].length; i++) {
                   let item = response[key][i];
                   item.name = await getUserItemName(username, item.id);
              }
            }
          }
          setTableData(response.data);
        }); 
    };
    
    useEffect(() => {
        getInitialData();
    }, []);
    

    I updated the loop to for loop, instead of forEach.forEach doesn’t wait for each asynchronous operation to finish before moving on to the next iteration. This can result in race conditions or out-of-order execution of asynchronous tasks.

    Also, where are you storing the response from getUserItemName ? as outside the scope and on every loop you’re losing the item.name

    Login or Signup to reply.
  3. you can use the map and promise all to get the data for all the data received from the first API call.

    Try this :

    const getUserItemName = async(Id) => {
      try {
        const response = await
        fetch(`https://jsonplaceholder.typicode.com/users/${Id}`);
        const data = await response.json();
        return data.id;
      } catch (error) {
        console.error('Error fetching item name:', error);
        return ''; //Empty string incase of error 
      }
    };
    
    
    const fetchData = async() => {
      try {
        const response = await fetch('https://jsonplaceholder.typicode.com/posts');
        const data = await response.json();
    
        // Using Promise.all to wait for all getUserItemName 
        await Promise.all(data.map(async(item) => {
          item.name = await getUserItemName(item.userId);
        }));
    
        // After all the data has been retrieved from the first API call and      //processed, the second API call is made before logging the data.
        console.log(data);
      } catch (error) {
        console.error('Error fetching data:', error);
      }
    };
    
    fetchData();
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search