Search code examples
javascriptarraysobjectsoliditypush

I can’t seem to find where I did or did not use the await keyword right


I have been bugged down for 2 days straight trying to figure out where I messed up but I can’t come to terms Here’s a full breakdown of the code I wrote

useEffect(() => {
const main = async () => {
  const profileData = [];
  try {
    coll.map(async (col) => {
      const instance = new Contract(col, nftABI, provider);
      const balance = await instance.balanceOf(profile);
      let profileBalance = balance.toNumber();
      const tokenIds = [];
      const name = [];
      const images = [];
      for (let i = 0; i < profileBalance; i++) {
        if (profileBalance > 0) {
          console.log(profileBalance, i, col);
          const tokenId = await instance.tokenOfOwnerByIndex(profile, i);
          let NumTokenId = tokenId.toNumber();
          let StrTokenId = String(NumTokenId);
          const uri = await instance.tokenURI(StrTokenId);
          const url = uri.replace(
            "ipfs://",
            "https://gateway.pinata.cloud/ipfs/"
          );
          const ipfsFile = await fetch(url).then((r) => r.json());
          const imageUri = ipfsFile.image.replace(
            "ipfs://",
            "https://gateway.pinata.cloud/ipfs/"
          );
          name.push(ipfsFile.name);
          images.push(imageUri);
          tokenIds.push(StrTokenId);
        }
      }
      const obj = {
        collection: col,
        tokenArray: tokenIds,
        image: images,
        name: name,
      };
      if (obj.name.length > 0) {
        profileData.push(obj);
      }
    });
  } catch (error) {
    console.log(error);
  }
  setR(profileData);
};
main();

}, []);

r, my useState variable comes back as an empty array and it console.logs first before the data has finished populating What am I doing wrong please


Solution

  • coll.map
    

    The map function knows nothing about promises or async functions. It will synchronously loop through the array, create a new array with the return values from your function, and then carry on.

    Since coll.map will be creating an array of promises, you should use that array:

    const profileData = [];
    try {
      const promises = coll.map(async (col) => {
        // ...
      });
      await Promise.all(promises);
    } catch (error) {
    

    Additionally, instead of pushing to an external array, you can return the values from your map function, and the promises will resolve to those values. This will let your resulting array be in the same order as the input coll array, and it will be using map as it was intended. In your particular case, you'll need some filtering, since you want to exclude ones with no name.

    // No longer creating profileData here
    try {
      const promises = coll.map(async (col) => {
        // ...
        const obj = {
          collection: col,
          tokenArray: tokenIds,
          image: images,
          name: name,
        };
        return obj
      });
      let profileData = await Promise.all(promises);
      profileData = profileData.filter(obj => obj.name.length > 0);
      setR(profileData);
    } catch (error) {