Home > Blockchain >  Multiple concurrent axios requests on React
Multiple concurrent axios requests on React

Time:09-09

I have a situation that I can not solve for some reason.

Let me explain what I'm trying to do:

I am trying to get number of crypto tokens received by entering a contract and an address (which helps me to reach out the API results).

For the moment, it works like this: https://thecryptoguetter.netlify.app/pages/HowMuchGlobal

So as you can see, I ask the user to chose a network (because API endpoints are different but they are all structured the same way)

My goal: Allowing users to simply enter a contract and an address, and I'll manage to get the right answer on my side.

What do I need:

I need to make multiple requests and get the answer of the one which works. For that, this is quite easy on the paper, the message in the API is "OK" if it's ok, and "NOTOK" if not. Simple ahah

But for some reason, I'm drowning with the logic, and tried multiple things but my brain is bugging hard on this one.

Here is what I did:

import axios from "axios";

const HowMuchTest = () => {
  const [tokenContract, setTokenContract] = useState("");
  const [address, setAddress] = useState("");
  const [answerAPI, setAnswerAPI] = useState([]);
  const [total, setTotal] = useState([]);
  const [decimals, setDecimals] = useState(18);
  const [txDatasArray, setTxDatasArray] = useState();

  const handleTokenContract = (event) => {
    const searchTokenContract = event.target.value;
    setTokenContract(searchTokenContract);
  };

  const handleAddress = (event) => {
    const searchAddress = event.target.value;
    setAddress(searchAddress);
  };

  const clearToken = () => {
    setTokenContract("");
    setAddress("");
    setTotal([]);
  };

  useEffect(() => {
    axios
      .all([
        axios.get(
          `https://api.bscscan.com/api?module=account&action=tokentx&contractaddress=${tokenContract}&address=${address}&page=1&offset=100&startblock=0&endblock=27025780&sort=asc&apikey=[KEY]`
        ),
        axios.get(
          `https://api.etherscan.io/api?module=account&action=tokentx&contractaddress=${tokenContract}&address=${address}&page=1&offset=100&startblock=0&endblock=27025780&sort=asc&apikey=[KEY]`
        ),
      ])
      .then(
        axios.spread((...res) => {
          setAnswerAPI(res);
        })
      );
  }, [address, tokenContract]);

  console.log(answerAPI[0].data);

  useEffect(
    (answerAPI) => {
      if (answerAPI[0].data.message === "OK") {
        setTxDatasArray(answerAPI[0]);
      } else if (answerAPI[1].data.message === "OK") {
        setTxDatasArray(answerAPI[1]);
      }
    },
    [answerAPI]
  );

  console.log(txDatasArray);

  useEffect(() => {
    let dataArray = [];
    for (let i = 0; i < answerAPI.length; i  ) {
      let toLower = answerAPI[i]?.to?.toLowerCase();
      let addressLower = address?.toLowerCase();
      if (toLower === addressLower) {
        dataArray.push({
          ticker: answerAPI[0].tokenSymbol,
          value: Number(answerAPI[i].value),
        });
      }
    }
    setDecimals(Number(answerAPI[0]?.tokenDecimal));
    setTotal(dataArray);
  }, [address, answerAPI, decimals]);

  const totaltotal = total.reduce((a, v) => (a = a   v.value), 0);

  const FinalTotal = () => {
    if (decimals === 6) {
      return (
        <div>
          {(totaltotal / 1000000).toFixed(2).toLocaleString()} {total[0].ticker}
        </div>
      );
    } else if (decimals === 18) {
      return (
        <div>
          {(totaltotal / 1000000000000000000).toFixed(2).toLocaleString()}{" "}
          {total[0].ticker}
        </div>
      );
    }
  };

  return (
    <div className="how-much">
      <div className="received-intro">
        <h1>Find out how much did you receive on a particular token</h1>
      </div>
      <div className="token-contract">
        <input
          type="text"
          placeholder="Token Contract Address"
          value={tokenContract}
          onChange={handleTokenContract}
        />
        <input
          type="text"
          placeholder="ERC20 Address"
          value={address}
          onChange={handleAddress}
        />
      </div>
      {totaltotal !== 0 && (
        <div className="show-total-received">
          <div className="total-received">
            <FinalTotal />
          </div>
          <div>{total.ticker}</div>
        </div>
      )}
      <button className="btn btn-info" onClick={clearToken}>
        Clear
      </button>
    </div>
  );
};

export default HowMuchTest;

The part to look is the two first useEffect.

I get the following answer from the console: Cannot read properties of undefined (reading 'data')

Which is weird because I can reach answerAPI[0].data in the first console.log

So yes, I'm totally lost and can't figure it out. I tried a for loop in a useEffect too but it ended in an infinite loop...

Thank you in advance for the ones who will read until there!

Have a good day

CodePudding user response:

The problem is in your useEffect implementation. The function passed to useEffect does not take any arguments, so answerAPI as written will always be undefined, because inside this function it is the non-existing argument, and not your state as you might have expected.

You can change it to:

useEffect(() => {
    if (answerAPI[0]?.data?.message === "OK") {
      setTxDatasArray(answerAPI[0]);
    } else if (answerAPI[1]?.data?.message === "OK") {
      setTxDatasArray(answerAPI[1]);
    }
  }, [answerAPI]);
  • Related