How can I fetch an api inside a loop and wait some seconds after each fetch?

Viewed 66

Hello everyone and thank you for taking your time to read through my question. I am currently sitting on my first react native app where I fetch a lot of data with an API.

I want to iterate through a loop and fetch data at every iteration. Unfortunately I get the "Too many requests error". Reason is, I can only fetch every 5 seconds according to my API Provider.

Therefore I tried to solve the problem with setTimeout as recommended on other posts. But it doesn't work. I can put the setTimeout function everywhere in the code and it always waits 5 seconds. Besides when I put it in the loop (where I think it belongs). Then it just does nothing and iterates normally through the loop.

How would you solve that?

function Overview() {
  function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
  }

  async function fetchETFData(props) {
    try {
      const response = await fetch("URL_API" + props);
      const testData = await response.json();
      console.log(testData);
    } catch (error) {
      console.error(error);
    }
  }

  async function userData() {
    try {
      const response = await fetch("URL_Database");
      // Fetch data from a database and then iterate threw that data and fetch with that data from an API

      const userDataFetch = await response.json();

      for (var key in userDataFetch) {
        userDataFetch[key].forEach(async function (element) {
          await sleep(5000);
          let fetchSymbol = element.symbol;
          fetchETFData(fetchSymbol);
        });
      }
    } catch (error) {
      console.error(error);
    }
  }

  userData();

  return (
    <div>
      <Button
        onPress={ShareOfPositions}
        title="Calculate Shares"
        color="#841584"
        accessibilityLabel="Learn more about this purple button"
      />
    </div>
  );
}
1 Answers

In your for loop, change await sleep(5000) to sleep(5000 * (index+1)) where index is the current element index that forEach gives us. This way you make sure between each there is 5s as you wanted:

userDataFetch[key].forEach(async function (element, index) {
  await sleep(5000 * (index+1));
  let fetchSymbol = element.symbol;
  fetchETFData(fetchSymbol);
});

And here his your whole component where I added the function in a useEffect to make sure it runs only once:

import {useEffect} from "react";
function Overview() {
  useEffect(() => {
    function sleep(ms) {
      return new Promise((resolve) => setTimeout(resolve, ms));
    }
    async function fetchETFData(props) {
      try {
        const response = await fetch("URL_API" + props);
        const testData = await response.json();
        console.log(testData);
      } catch (error) {
        console.error(error);
      }
    }
    async function userData() {
      try {
        const response = await fetch("URL_Database");
        const userDataFetch = await response.json();

        for (var key in userDataFetch) {
          userDataFetch[key].forEach(async function (element, index) {
            await sleep(5000 * (index+1));
            let fetchSymbol = element.symbol;
            fetchETFData(fetchSymbol);
          });
        }
      } catch (error) {
        console.error(error);
      }
    }
    userData();
  }, []);

  return (
    <div>
      <Button
        onPress={ShareOfPositions}
        title="Calculate Shares"
        color="#841584"
        accessibilityLabel="Learn more about this purple button"
      />
    </div>
  );
}
Related