2

I am trying to make a counter that counts how many NFTs are minted. I have an async function, getTotalTokensMinted, that gets the total number of tokens minted from a smart contract. How do I render the HTML so it displays the return value, numTokens, from getTotalTokensMinted? Should I use useState hook or local storage?

The code I have below returns a

Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render
import React, { useEffect, useState } from 'react';
import { ethers } from 'ethers';
import './styles/App.css';
import myEpicNFT from './utils/MyEpicNFT.json';

const TOTAL_MINT_COUNT = 3;
const CONTRACTADDRESS = "0x6fe91f4814f372Eb40B547114CD75B76DF5f53dC";

const App = () => {

//const [NFTsMinted, NFTcounter] = useState(0);

 const getTotalTokensMinted = async () => {
   const { ethereum } = window;
   let numTokens;
   try {

     if (ethereum) {
       const provider = new ethers.providers.Web3Provider(ethereum);
       const signer = provider.getSigner();
       const connectedContract = new ethers.Contract(contractAddress, contractABI, signer);

       numTokens = await connectedContract.getTokenNumber();
       return numTokens;
      } 
   } catch (error){
       console.log(error);
   }
   return(
     <div> {numTokens}</div>
   );
 }

return (
   <div className="App">
     <div className="container">
         <p className = "sub-text">
         NFT MINTED = {getTotalTokensMinted} / { TOTAL_MINT_COUNT }
         </p>
       </div>
     </div>
   </div>
 );


}

4 Answers 4

1

Your code could quickly get confusing as you develop more functionality. As a rule of thumb, it's good to separate the business logic of your app from the UI.

Try putting your getTotalTokensMinted function in an /api folder or /utils. That function doesn't need to be a component; it simply needs to return a value...

const getTotalTokensMinted = async () => {
   const { ethereum } = window;
   let numTokens;
   try {

     if (ethereum) {
       const provider = new ethers.providers.Web3Provider(ethereum);
       const signer = provider.getSigner();
       const connectedContract = new ethers.Contract(contractAddress, contractABI, signer);

       numTokens = await connectedContract.getTokenNumber();
       return numTokens;
      } 
        return null

   } catch (error){
       console.log(error);
   }

And then in the component you actually want to display the minted count you can simply declare a variable count (or whatever) which will store the number of tokens.

const App = () => {
const count = await getTotalTokensMinted();
return (
   <div className="App">
     <div className="container">
         <p className = "sub-text">
         NFT MINTED = {count} / { TOTAL_MINT_COUNT }
         </p>
       </div>
     </div>
   </div>
 );

}
Sign up to request clarification or add additional context in comments.

Comments

0

You may want to get the function returned value like this

return (
   <div className="App">
     <div className="container">
         <p className = "sub-text">
         NFT MINTED = {getTotalTokensMinted()} / { TOTAL_MINT_COUNT }
         </p>
       </div>
     </div>
   </div>
 );

If you get an array object error you need to change on how you return the value in the function like this :

return (
    <div> {numTokens?.map((each)=>{
           <div>{each}</div>
           })}
   </div> 
)

2 Comments

I tried that, but I got an Uncaught Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
@EmilyKuo I've edited the question based on your error please accept answer If it helped you in anyway .
0

You need to wrap your component in the proper syntax:

example: <Route exact path="/" element={Home}

Will give you this same error...Need to correct to this:

<Route exact path="/" element={}

Comments

0

From react point of view you want some async operation and its output in DOM. According to provided code snippet you are calling getTotalTokensMinted in the DOM with incorrect syntax. As a solution you need to call async function in useEffect hook with no dependency to render as componentDidMount. You need local state to store result and then use that state in the DOM.

Steps

Follow these steps as a solution

Define local state

By using useState you can create local state. You can use global state depends on the requirement

const [NFTsMinted, setNFTsMinted] = useState(0);

Async function

Set state in async function as follow

const getTotalTokensMinted = async () => {
    const { ethereum } = window;
    
    if (ethereum) {
      const provider = new ethers.providers.Web3Provider(ethereum);
      const signer = provider.getSigner();
      const connectedContract = new ethers.Contract(contractAddress, contractABI, signer);

      const numTokens = await connectedContract.getTokenNumber();
      setNFTsMinted(numTokens)
    } 
  }

Call async function

Use useEffect hook to call function

  useEffect(() => {
    getTotalTokensMinted()
  }, [])

Display results in DOM

Use state variable to display counts

<div className="App">
  <div className="container">
    <p className = "sub-text">
      NFT MINTED = {NFTsMinted} / { TOTAL_MINT_COUNT }
    </p>
  </div>
</div>
    

3 Comments

ah I tried that, but I got "Objects are not valid as a React child" error. I think it is something when I incorporated the getTotalTokensMinted in useEffect. I am trying to persist the numTokens value even when the browser refreshes and wouldn't it reset to zero if useState is initialized to zero?
Can you show me what is stored in NFTsMinted after fetching? You can console by writing console.log(numTokens) above setNFTsMinted(numTokens). Second thing if you want to see results after refreshing then you should store this numTokens in cookies or local storage you can use npmjs.com/package/react-cookie for storing cookies
Possibly you are not getting correct (number) type from getTokenNumber() function

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.