Home > Software design >  How to set fetch limit in useEffect?
How to set fetch limit in useEffect?

Time:11-01

In my project i am trying to fetch in one time more than 5 API's together, but when i fetch using useEffect, it's continuously fetching, never stop fetching. so for that i want to set a limit for that.

is that possible to set a limit on useEffect to fetch 10 times and then it will stop fetching automatically?

Here is my codes:


const [dosa, setDosa] = useState([]);

    const hola= () => {
        const haspi = dv?.map((id) => {
            fetch(`https://www.roads.com/roads/roadscontroll/${id}`)
                .then((response) => response.json())
                .then((dosa) => setDosa((prev) => [...prev, [dosa]))
                .catch((error) => console.error(error))
        })
        return haspi ;
    }


    useEffect(() => {
        hola();
    });

here it's fetching continuously, so i want to set a limit for that. how can i do that for my codes? any one can help me to do that. Thanks for your helping in advance!

Note: for security reason i am using here false API.

CodePudding user response:

You could do something like this:

Solution 1: Add dependency array to the useEffect.

const [dosa, setDosa] = useState([]);

const hola= () => {
    const haspi = dv?.map((id) => {
        fetch(`https://www.roads.com/roads/roadscontroll/${id}`)
            .then((response) => response.json())
            // To avoid confusion use different name for the received data: dosa -> newDosa
            .then((newDosa) => setDosa((prev) => [...prev, [newDosa])) 
            .catch((error) => console.error(error))
    })
    return haspi ;
}


useEffect(() => {
    hola();
}, []); // Add empty dependency array here

Adding an empty dependency array prevents the useEffect from being called on every render. This way it is called only on the component mount.

This issue is occurring because you are calling setDosa on API success which causes the dosa state to update and the component to re-render and this causes the useEffect (with no dependency) to get called over and over again in a "loop".

More info on the difference between no dependency array and an empty dependency array over here: https://stackoverflow.com/a/66385496/7040601


Solution 2: Below is a less elegant solution to store the counter using a ref object and setting a limit to the counter.

const [dosa, setDosa] = useState([]);
const counterRef = useRef(0); // Ref initialied to value = 0
const limit = 3;

const hola= () => {
    const haspi = dv?.map((id) => {
        fetch(`https://www.roads.com/roads/roadscontroll/${id}`)
            .then((response) => response.json())
            .then((newDosa) => setDosa((prev) => [...prev, [newDosa]))
            .catch((error) => console.error(error))
    })
    return haspi ;
}


useEffect(() => {
    // Only call `hola()` if counter is within the limit
    if(counterRef.current < limit) 
        hola();
    counterRef.current  ; // Increment the counter by 1
});

Note: In addition to this, I agree with @Peter Tam's suggestion in the comments, you may apply it on top of the above solutions:

I perfer to use a temp array to store all the fetch records, and set state at last instead of setting state everytime after fetch request is returned. Maybe there are issues for using not updated states. You may follow the answer like here.

CodePudding user response:

You should not use useEffect to run API calls a fixed number of times for two reasons.

  1. When the API calls don't work as expected, you can't be always sure that they'll work within, say, 10 attempts (if the service was down, for example).
  2. When they do work, say, on the second attempt, the remaining 8 times you make the calls are just a waste of precious resources.

What you should instead do is to check the outcome of the API calls, and run the useEffect hook based on that. In your case, if the API call were successful, dosa array would be populated. Then your useEffect hook becomes this:

useEffect(() => {
  if (!dosa.length) {
    hola(); // only runs if array is not yet populated.
  }, [dosa.length]); // hook runs every time the array length changes.
  • Related