2 years ago

#11877

test-img

yieniggu

Memorizing values upon an async call in react

I'm trying to memorize some values in a react component because it's re rendering even when data hasn't changed (and wont change). Using useEffect + useState the data displays correctly, but the functions are triggered each time the component is re rendered. Currently am trying to implement the useMemo hook but the async call/promise is not resolving in the render process, so it doesn't even loads the data. I'll try to give the most information out of this:

This is my AppRouter component, i create the contract and pass it as value to a provider that will be used in some other components:

import { useWeb3React } from "@web3-react/core";
import React, { useEffect, useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";

import { AdminScreen } from "../components/admin/AdminScreen";
import { ContractsContext } from "../components/ContractsContext";
import { Navbar } from "../components/ui/Navbar";
import { getLibrary } from "../helpers/web3Getters";
import { useCreateContract, useGetLibrary } from "../hooks.js/contractsHooks";
import { createContract } from "../web3-utils/contractCreation";
import { MarketRoutes } from "./MarketRoutes";
import { PrivateRoute } from "./PrivateRoute";

export const AppRouter = () => {
  const context = useWeb3React();
  //console.log("[1] context in app router: ", context);

  const { contract: kolorTokenContract, loading: loadingContract } =
    useCreateContract(
      context,
      "0x9414f981a5B5ef2bE455f2427E2166c35e8989fB",
      "abis/KolorToken.json"
    );

  return (
    //<p>{loadingLibrary ? "library ready" : "loading library"}</p>

    <ContractsContext.Provider value={[kolorTokenContract]}>
      <BrowserRouter>
        <Navbar />
        {/* Set private route for Admining nfts & tokens */}
        <Routes>
          <Route
            path="/admin"
            element={
              <PrivateRoute>
                <AdminScreen />
              </PrivateRoute>
            }
          />

          <Route path="/*" element={<MarketRoutes />} />
        </Routes>
      </BrowserRouter>
    </ContractsContext.Provider>
  );
};

The contract is then obtained from my custom context in the admin route (which is what im testing now) and then passed to one of its children:

import React, { memo, useContext, useMemo } from "react";
import { getERC20Info } from "../../helpers/tokenGetters";
import { useGetERC20Info } from "../../hooks.js/contractsHooks";
import { ContractsContext } from "../ContractsContext";

export const TokenInfo = memo((tokenContract) => {
  //const { _address: ERC20Address } = tokenContract;
  const { address, owner, vault, supply } = useGetERC20Info(tokenContract);

  //const result = useMemo(() => getERC20Info(tokenContract), [tokenContract]);

  //console.log("contract from tokeninfo:", tokenContract);
  //console.log("result: ", result);

  return (
    <div className="row align-items-center">
      <div className="col-8 col-md-6 col-sm-4 ">Minting Form</div>
      <div className="col-4 col-md-3 col-sm-2 animate__animated animate__fadeInRightBig">
        <h2>Kolor Token Info</h2>
        <p>
          Address: <b>{address}</b>
        </p>
        <p>
          Owner: <b>{owner}</b>
        </p>
        <p>
          Vault: <b>{vault}</b>
        </p>
        <p>
          Current supply: <b>{supply}</b>
        </p>
      </div>

      <hr />
    </div>
  );
});

Actually i'm using a custom hook with useState and useEffect to fetch the data, but it re renders the TokenInfo component even when the tokenContract hasn't changed at all. This is my custom hook:

export const useGetERC20Info = (contract) => {
  //console.log("contract from usegeterc20info effect: ", contract);

  const [state, setState] = useState({
    address: "loading...",
    owner: "loading...",
    vault: "loading...",
    supply: "loading",
  });

  useEffect(() => {
    getERC20Info(contract).then(({ address, owner, vault, supply }) => {
      setState({
        address,
        owner,
        vault,
        supply,
      });
      return () => {
        setState({});
      };
    });
  }, [contract]);

  return state;
};

My getERC20Info function, tries to fetch data from the blockchain, nothing wrong with that, its working fine:

export const getERC20Info = async (contract) => {
  console.log("getting erc20 info...");
  console.log("contract from geterc20info: ", contract);

  const { _address: address } = contract;
  const owner = await getERC20Owner(contract);
  const vault = await getERC20Vault(contract);
  const supply = await getERC20Supply(contract);

  //console.log("supply: ", supply);

  return {
    address,
    owner,
    vault,
    supply,
  };
};

Thanks in advance for any help!

javascript

reactjs

use-effect

use-state

react-usememo

0 Answers

Your Answer

Accepted video resources