Home > front end >  Create an array within a 'for loop' in React
Create an array within a 'for loop' in React

Time:08-01

I have picked up a React project that uses Polkadot.js from another developer and I'm struggling to understand how to achieve the following:

I want to display a grid of images. The initial part of the image URL is hardcoded in a const.

When the user clicks on a button, the user's account is checked asynchronously to see what NFT's they own. However there isn't an array/object what I need, so I have to create an array using the hardcoded URL, along with the provided number and add the image file extension at the end of the string. eg. imageURL imageNumber '.png'

The async function that is called on click is as follows:

const getNFT = async (address: string) =>  {
    const wsProvider = new WsProvider(wsUrl);
    const api = await ApiPromise.create({ provider: wsProvider });

    // NOTE the apps UI specified these in mega units -> https://polkadot.js.org/docs/api-contract/start/contract.read
    // @ts-ignore
    const gasLimit = -1;
    // Read from the contract via an RPC call
    const value = 0; // only useful on isPayable messages -> https://polkadot.js.org/docs/api-contract/start/contract.read

    // @ts-ignore
    const contract = new ContractPromise(api, abi, contractAddress);

    const {gasConsumed, result, output} = await contract.query['psp34::balanceOf'](address, {value: 0, gasLimit: -1}, address);
    console.log(JSON.stringify(result.toHuman()));
    if (result.isOk) {
      // should output 123 as per our initial set (output here is an i32)
      // @ts-ignore
      setUserNFTCount(output.toHuman());

      // @ts-ignore
      console.log('Number of NFT you own:', output.toHuman());

      // @ts-ignore
      for (let i = 0; i <= output.toNumber() - 1; i  ) {
        console.log ("Getting NFT at index "   i);
        const NFTIndexResult = await contract.query['psp34Enumerable::ownersTokenByIndex'](address, { value: 0, gasLimit: -1 }, address, i);
        
        if (NFTIndexResult.result.isOk && NFTIndexResult.output != null) {
          console.log(NFTIndexResult);
          console.log(NFTIndexResult.output.toHuman())
           // @ts-ignore
          var pNumber = NFTIndexResult.output.toHuman().Ok.U64;
          console.log('NFT number you own:'   pNumber);

          var metadata = metadataUrl   pNumber   '.json';
          var image = imageUrl   pNumber   '.png';

          console.log('TODO, show image: '   image);
          let myImageArray = [];
          myImageArray.push(image)
          console.log('array = '   myImageArray);
        }
      }

    } else {
      console.error('Error', result.asErr);
    }
  }

When I check my console, I can see the individual images I want to add to an array within the image variable. But I'm not sure how to add each image into a single array which I can then use to render a grid of the images.

CodePudding user response:

Declare the array outside the loop so it isn't declaring a new array each iteration.

Example:

const myImageArray = []; // <-- declare prior to loop

// @ts-ignore
for (let i = 0; i <= output.toNumber() - 1; i  ) {
  console.log ("Getting NFT at index "   i);
  const NFTIndexResult = await contract.
    query['psp34Enumerable::ownersTokenByIndex'](
      address,
      { value: 0, gasLimit: -1 },
      address,
      i,
    );
    
  if (NFTIndexResult.result.isOk && NFTIndexResult.output != null) {
    console.log(NFTIndexResult);
    console.log(NFTIndexResult.output.toHuman());
    // @ts-ignore
    var pNumber = NFTIndexResult.output.toHuman().Ok.U64;
    console.log('NFT number you own:'   pNumber);

    var metadata = metadataUrl   pNumber   '.json';
    var image = imageUrl   pNumber   '.png';

    console.log('TODO, show image: '   image);
      
    myImageArray.push(image); // <-- push all into same array
    console.log('array = '   myImageArray);
  }
}

Presumably you'll be doing something with myImageArray after the loop.

CodePudding user response:

It seems your issue is that of scope. I assume you are looking to have the array of image url's outside of the async function:

const getNFT = async (address: string) => 

I see you declared a local variable myImageArray inside the for loop. This will cause a number of issues. It, at minimum, needs to be outside the for loop so you don't override your variable with a new empty array, erasing all your data.

There are a number of approaches to this problem, but probably the best would be to collect your results, similar to your current approach, but then return the values from the function. See the below example:

const myImageArray = []; // Declare your array here so if you fail to retrieve you are returning an empty array (if that is your desired behavior)

console.log(JSON.stringify(result.toHuman()));
if (result.isOk) {
    // should output 123 as per our initial set (output here is an i32)
    // @ts-ignore
    setUserNFTCount(output.toHuman());

    // @ts-ignore
    console.log('Number of NFT you own:', output.toHuman());

    // @ts-ignore

    for (let i = 0; i <= output.toNumber() - 1; i  ) {
        console.log("Getting NFT at index "   i);
        const NFTIndexResult = await contract.query['psp34Enumerable::ownersTokenByIndex'](address, { value: 0, gasLimit: -1 }, address, i);

        if (NFTIndexResult.result.isOk && NFTIndexResult.output != null) {
  
            // removed for brevity
            var image = imageUrl   pNumber   '.png'
            myImageArray.push(image);
        }
    }

} else {
    console.error('Error', result.asErr);
}
return myImageArray; // return the array, as that is the data you seem to want out of the function

Then you can use your function elsewhere like so:

const imageArray = await getNFT('someAddress')
  • Related