Rendering NFTs owned

All the code will be inserted into the MainMenu file

Now that we have a function to fetch all NFTs owned by the user, we want to give him an interface to see them. For this, we will have to store the complete list of ids using a constant inside the MainMenu component. We will be doing this using the same React State hook, so import it into MainMenu.js file. In addition, React Callback hook will be needed.

import React, { useEffect, useState, useCallback } from 'react';

Create the needed states

After importing the needed hooks, the next step is creating the constant to store the results. It will be a constant having attached a function to access its value by the State hook. We initialize it having the value of an empty list []. Also, we will need a boolean constant to record whether the API has responded and we can start rendering the results. When first getting on the MainMenu, obviously the results haven’t already been obtained, this is why we are initializing our constant being false.

const [NFTsOwned, setNFTsOwned] = useState([]);
const [hasRespondedNFTs, setHasRespondedNFTs] = useState(false);

Ensure waiting for the results by an async function

An arrow function that does the fetching steps will be needed, too. Keeping in evidence the fact that we need to wait for the response, the constant will be an asynchronous one. We are going to use the Callback hook because we only need to execute it once, unless the userAddress is modified. This is why userAddress is the unique Callback parameter.

const fetchNFTsOwned = useCallback(async () => {
  let localNFTsOwned = await getNFTsOwned(userAddress);
  setHasRespondedNFTs(true);
  if (localNFTsOwned) setNFTsOwned(localNFTsOwned);
  else setNFTsOwned([]);
}, [userAddress]);

As you see above, after waiting for the API’s response, we will set the hasRespondedNFTs constant’s value to true, meaning the interaction with the API has completed. If the local variable localNFTsOwned has at least one value, we will set the NFTsOwned constant’s value to the respective list of ids. If not, NFTsOwned will keep having the empty list [] value meaning the user does not own any NFTs. To give functionality to our fetchNFTsOwned constant, we will call it using the Effect hook previously explained. To cover any eventual changes to the user wallet balance, we are going to set an interval of 30 seconds in which the execution thread will be reloaded and the NFTs list will be updated.

useEffect(() => {
  fetchNFTsOwned();
  setInterval(() => {}, 30000);
}, [fetchNFTsOwned]);

Render based on previous states

Using NFTsOwned and hasRespondedNFTs states, we can build the cases in which the user can fit.

  1. The first one is when the API hasn’t responded yet. So we will return the corresponding <HTML> content which sends the message that the NFTs are still loading:

    {!hasRespondedNFTs && <h1> Loading NFTs... </h1>}
  2. The second one is when the API has responded, but the user does not own any NFTs:

    {hasRespondedNFTs && NFTsOwned.length == 0 && <h1> No NFTs available </h1>}
  3. The last one happens when the API has responded, and the user owns at least one NFT:

    {hasRespondedNFTs && NFTsOwned.length > 0 && (
      <div>
        <h2>Pick your NFT!</h2>
        {NFTsOwned.map((nftId) => (
          <span id={`nft${nftId}`} key={nftId}>
            <img
              src={`https://stacksgamefi.mypinata.cloud/ipfs/QmNz74TN66hgi9X4wZ1ch9hXKxaywG5soEQPMfDqEMLVsd/${nftId}.png`}
              alt={`duck ${nftId}`}
              width="50"
            ></img>
            {`NFT#${nftId}`}
          </span>
        ))}
      </div>
    )}

Render and return the NFTs by cases

The .map() does nothing but mapping each nftId from NFTsOwned to its corresponding <HTML> representation for the user experience. This way the user will see all the NFTs with the corresponding images and a suggestive name below each image. As you see above, the <img>'s src is written using the base Pinata url and the NFT’s id which could be found in NFTsOwned list. The final look of the returned content inside MainMenu will be the following:

return (
  <div>
    <header className="App-header">
      <h1>Integrate NFTs Into GameFi</h1>
      <h6>{`Current user address: ${userAddress}`}</h6>
      {!hasRespondedNFTs && <h1> Loading NFTs... </h1>}
      {hasRespondedNFTs && NFTsOwned.length == 0 && <h1> No NFTs available </h1>}
      {hasRespondedNFTs && NFTsOwned.length > 0 && (
        <div>
          <h2>Pick your NFT!</h2>
          {NFTsOwned.map((nftId) => (
            <span id={`nft${nftId}`} key={nftId}>
              <img
                src={`https://stacksgamefi.mypinata.cloud/ipfs/QmNz74TN66hgi9X4wZ1ch9hXKxaywG5soEQPMfDqEMLVsd/${nftId}.png`}
                alt={`duck ${nftId}`}
                width="50"
              ></img>
              {`NFT#${nftId}`}
            </span>
          ))}
        </div>
      )}
      <button className="Connect" onClick={disconnect}>
        Disconnect Wallet
      </button>
      <br></br>
      <a className="App-link" href="<https://stacksdegens.com/>" target="_blank">
        Build by Stacks Degens
      </a>
    </header>
  </div>
);

After completing this step, our MainMenu offers the user an interface where he can see all the NFTs he owns. Next, we want to give him the possibility to click each one in order to select it and finally play using it.

This is the branch with the changes done:

You can check the exact changes in this commit referring to them

Last updated