Changing UI dynamically on contract call with React-Moralis (documenting my method for others)

This is a post where I document how I change UI on a successful contract function call. Keeping this here to help others who might have the same query (and save them 2 days of pain :smile:) :

  1. Call a smart contract function by clicking a button “Approve My Traits” (see “before” screenshot).
  2. On successful txn, I deactivate the button, gray it out and change button to “Traits Approved” (see “after” screenshot).
  3. If user returns to the site after a while or refreshes, I use useEffect to make a function call and check if approved==false or approved==true and accordingly render the active button or grayed out button.
  4. If user switches accounts in metamask I trigger the above useEffect again to check and re-render button.
    Hat-tip to @PatrickAlphaC whose solution here helped. Also thanks to @orangemat @_Ty for their inputs.

The code below is self explanatory. Any suggestions welcome. I have not implemented error catching so any suggestion on that is appreciated.

function SetApproval() {
  //isApprovedForAll(account, operator) - function imported in our contract from OpenZeppelin IERC1155
  //setApprovalForAll(operator, approved) - function imported in our contract from OpenZeppelin IERC1155

    const spotTraitsContractFuji = '0xD1cebaDdf3a76CD1E628e8Ce541fC700c64Afe47';
    const spotNFTContractFuji = '0x1BcaC9c748619578B8b420ff4E5536a55441fc42';
    const { account } = useMoralis();

    const { data: approvalData, error: approvalError, 
fetch: approvalFetch, isFetching: approvalFetching,
 isLoading: approvalLoading } = useWeb3ExecuteFunction({
        abi: spotTraitsAbiFuji, //imported from spotTraitsAbiFuji.json
        contractAddress: spotTraitsContractFuji,
        functionName: "setApprovalForAll",
        params: {
        operator: spotNFTContractFuji,
        approved: true
             },
         });

    const { data: checkApprovedData, error: checkApprovedError, 
fetch: checkApprovedFetch, isFetching: checkApprovedFetching, 
isLoading: checkApprovedLoading } = useWeb3ExecuteFunction({
    abi: spotTraitsAbiFuji,
    contractAddress: spotTraitsContractFuji,
    functionName: "isApprovedForAll",
    params: {
        account: account,
        operator: spotNFTContractFuji
            },
        });
    const [traitsApproved, setTraitsApproved] = useState(false)
    
    function changeUITrue() {
        setTraitsApproved(true)
    }
    function changeUIFalse() {
        setTraitsApproved(false)
    }

    const handleSuccessfulApproval = async (tx) => {
        await tx.wait(1)
        changeUITrue()
    }

    useEffect(()=>{
      const checkApproval = async ()=>{
        const result = await checkApprovedFetch();
        if (result) {
          changeUITrue();
        } else changeUIFalse();
      }
      checkApproval()
    },[account])
   
    return (
    <div>
        <button className={!traitsApproved?"m-2 rounded-lg px-4 py-2 border-2 border-gray-200 text-gray-200 hover:bg-gray-200 hover:text-gray-900 duration-300 font-mono font-bold text-base":"m-2 rounded-lg px-4 py-2 border-2 border-gray-200 bg-gray-500 text-gray-900 font-mono font-bold text-base"} 
     onClick={async()=>{
     if(traitsApproved){
        return;
     }
     await approvalFetch({
         onSuccess: handleSuccessfulApproval,
     })
     }}>{traitsApproved?'Traits Approved':'Approve My Traits'}</button>
    </div>
  )
}
export default SetApproval;

before

5 Likes

Great article. :clap: Thanks @zubin !!!

1 Like