Home > Mobile >  Making an API request every X amount of seconds in reactJS
Making an API request every X amount of seconds in reactJS

Time:11-27

On entering CurrencyPage, I am trying to get the list of currencyConversionRates from database and then subsequently set an interval to constantly get the new updated list of currencyConversionRates every 6 seconds.

Up till this point, everything works fine. However, I am unable to pass the value of the setInterval to the cleanup function. The value being returned is always in the format of a promise

Promise {<fulfilled>: 1}

How can I pass the setInterval value to the cleanup function so that the interval stops being executed upon navigating to other pages

Use Effect

useEffect(() => {
    const getCurrencyConversionRates=async()=>{
        console.log("Retrieving list of currency conversion rate");
        await retrieveCurrencyConversionRateFunction();

        //Gets new information every 6 seconds
        const intervalCall = setInterval(async() => {
            console.log("Getting new currency conversion rates!");
            const currTime = new Date().toLocaleTimeString();
            console.log("Time -> " currTime);
            await retrieveCurrencyConversionRateFunction();
        }, 60*100);


        //Have to wait until currencyConversionRateFunction is loaded before the map function is called on it in the render view otherwise will have error
        setLoading(false);
        return intervalCall;
    }

    let intervalCall = getCurrencyConversionRates();
    //Clear interval
    return () => {
        console.log("CLEARING CURRENCY INTERVAL HERE");
        console.log(intervalCall);
        clearInterval(intervalCall);
      };

},[]);

Solution Based on Azzy's answer Rather than to try and return the interval in getCurrencyConversionRates(), a simple alternative is to just initialize a variable to store the setInterval as it is created within the function.

Note to self -> It is not possible to pass a variable by reference through getCurrencyConversionRates() as a parameter as changes made to the variable wont be saved. However, in JS you can simply initialize the variable outside of the function and modify it's value from within the function.

https://www.javascripttutorial.net/javascript-pass-by-value/

useEffect(() => {
    
    const getCurrencyConversionRates=async()=>{
        // console.log("Retrieving list of currency conversion rate");
        await retrieveCurrencyConversionRateFunction();

        //Gets new information every 6 seconds
        intervalCall = setInterval(async() => {
            // console.log("Getting new currency conversion rates!");
            const currTime = new Date().toLocaleTimeString();
            console.log("Time -> " currTime);
            await retrieveCurrencyConversionRateFunction();
        }, 60*100);


        //Have to wait until currencyConversionRateFunction is loaded before the map function is called on it in the render view otherwise will have error
        setLoading(false);
        // return intervalCall;
    }

    let intervalCall;
    getCurrencyConversionRates();

    //Clear interval
    return () => {
        console.log("CLEARING CURRENCY INTERVAL HERE");
        console.log(intervalCall);
        clearInterval(intervalCall);
      };

},[]);

CodePudding user response:

This may help

useEffect(() => {

   let isValid = true;

   let intervalCall;

    const getCurrencyConversionRates = async () => {
        console.log("Retrieving list of currency conversion rate");
        await retrieveCurrencyConversionRateFunction();
        // after await if the component unmounts, and this scope 
        // becomes stale, skip futher execution   
        // so the interval wont be started, and wont break in dev mode where useEffect runs twice
        if (!isValid) { return; } 

        //Gets new information every 6 seconds
         intervalCall = setInterval( async () => {
            console.log("Getting new currency conversion rates!");
            const currTime = new Date().toLocaleTimeString();
            console.log("Time -> " currTime);
            await retrieveCurrencyConversionRateFunction();

            // might want to check valid scope inside 
            // retrieveCurrencyConversionRateFunction 
            // by passing it a flag to skip execution on a unmounted component scope

        }, 60*100);


        //Have to wait until currencyConversionRateFunction is loaded before the map function is called on it in the render view otherwise will have error
        setLoading(false);
    }

    getCurrencyConversionRates();
    //Clear interval
    return () => {
        console.log("CLEARING CURRENCY INTERVAL HERE");
        isValid = false
    
        // if interval was not stared, dont clear it
        if (intervalCall) {  clearInterval(intervalCall); } 
        console.log(intervalCall);
       
      };

},[]);

more about useEffect life cycle, to get an idea why

  • A new effect is created after every render
  • How the cleanup for previous effect occurs before executing of current useEffect

You can read about why isValid is set synchronizing with effects

If you are intererested in taking a deep dive, consider reading a blog post by Dan on useEffect, its old but explanation the details to build a good mental model about useEffects and functional components.

Hope it helps, cheers

  • Related