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