1

I have the following functional component where, on load of the component, it needs to loop through an array and run some async queries to populdate a new array I want to display in render method.

     import React, { useEffect, useState, useContext } from 'react';
     import { AccountContext } from '../../../../providers/AccountProvider';
     import { GetRelationTableCount } from '../../../../api/GetData';
     import { getTableAPI } from '../../../../api/tables';

  const RelatedRecordsPanel = (props) => {
  const { userTokenResult } = useContext(AccountContext);
  const { dataItem } = props;

  const [relatedTableItems, setRelatedTableItems] = useState([]);

   useEffect(() => {
      const tempArray = [];
      const schema = `schema_${userTokenResult.zoneId}`;
      const fetchData = async () => {

     return Promise.all(
        dataItem.tableinfo.columns
        .filter((el) => el.uitype === 1)
        .map(async (itm) => {
          const tblinfo = await getTableAPI(itm.source.lookuptableid);
          const tblCount = await GetRelationTableCount(
           dataItem.tableid,
          itm.source.jointable,
          schema,
        );

        const TableIconInfo = { name: tblinfo.name, icon: tblinfo.icon, count: tblCount };
        tempArray.push(TableIconInfo);

      })

  );
};
 fetchData();
setRelatedTableItems(tempArray)
 }, []);

  return (
     <div>
       {relatedTableItems.length > 0 ? <div>{relatedTableItems.name}</div> : null}
  </div>
  );
  };

In the above code, the queries run correctly and if I do a console.log in the loop, I can see if fetches the data fine, however, the array is always [] and no data renders. How do I write this async code such that it completes the queries to populate the array, so that I can render properly?

Thx!

mike hennessy
  • 1,359
  • 1
  • 16
  • 35

1 Answers1

2

You aren't using the return value of the Promise.all and since all your APIs are async, the tempArray is not populated by the time you want to set it into state

You can update it like below by waiting on the Promise.all result and then using the response

useEffect(() => {
      const schema = `schema_${userTokenResult.zoneId}`;
      const fetchData = async () => {

     return Promise.all(
        dataItem.tableinfo.columns
        .filter((el) => el.uitype === 1)
        .map(async (itm) => {
          const tblinfo = await getTableAPI(itm.source.lookuptableid);
          const tblCount = await GetRelationTableCount(
           dataItem.tableid,
          itm.source.jointable,
          schema,
        );

        const TableIconInfo = { name: tblinfo.name, icon: tblinfo.icon, count: tblCount };
        return TableIconInfo;

      })

  );
};
 fetchData().then((res) => {
     setRelatedTableItems(res);
 });

 }, []);
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
  • 1
    Thx, that works! I also just got it working by changging useEffect(async () ) and then using await fetchData(); setRelatedTableItems(tempArray) at the end. – mike hennessy Jun 16 '20 at 15:20
  • BTW, you should not make useEffect async, it will throw you a warning. https://stackoverflow.com/questions/53332321/react-hook-warnings-for-async-function-in-useeffect-useeffect-function-must-ret/53332372#53332372 – Shubham Khatri Jun 16 '20 at 15:22