Reputation: 57
I'm making an API call and if it fails, I need to call the API again after a set amount of time, however, I'm having trouble clearing the timeout due to the scope of the timeout.
This is working, but the timeout is able to be cleared:
React.useEffect(() => {
if (progress === 45 && !apiCallFailedRef.current) {
callApi();
}
function callApi(){
let requestData = {
method: 'GET',
path,
};
$.ajax(testPath, {
method: 'GET',
data: { data: JSON.stringify(requestData) },
})
.done(response => {
// setLoading(false);
})
.fail(response => {
console.log('failed')
apiCallFailedRef.current = true;
setTimeout(() => callApi(), 28000);
});
}
};
// How would I clear the timeout correctly?
// return () => {
// clearTimeout();
// };
}, [progress])
Upvotes: 1
Views: 1756
Reputation: 43
You can write a timeout to a ref and create a separate useEffect hook to clean up it only once on unmount.
// create a ref
const timeoutRef = useRef();
// in your useEffect
timeoutRef.current = setTimeout(() => callApi(), 28000);
// clean up useEffect
useEffect(() => {
return () => {
clearTimeout(timeoutRef.current);
}
}, []);
Upvotes: 1
Reputation: 81
I would recommend not trying to retry forever, you can use a specific number of retries, and each retry can also wait a little bit longer before it retries.
This would make an api call, retrying up to 5 times
function callApiWithRetry(url, options = {}, numRetries = 5, backoff = 250) {
return fetch(url, options)
.then(res => {
// if successful, return JSON response
if (res.ok) {
return res.json();
}
// not successful, retry until numRetry is 0
if (numRetries > 0) {
// make the api call again, but reduce the retry count, and double the backoff time
setTimeout(() => {
return callApiWithRetry(url, options, numRetries - 1, backoff * 2)
}, backoff);
} else {
// out of retries, something is wrong
throw new Error(res);
}
})
.catch(console.error);
}
Upvotes: 0
Reputation: 1768
You can assign the timeout to a variable as such:
React.useEffect(() => {
let timeout;
if (progress === 45 && !apiCallFailedRef.current) {
callApi();
}
function callApi(){
let requestData = {
method: 'GET',
path,
};
$.ajax(testPath, {
method: 'GET',
data: { data: JSON.stringify(requestData) },
})
.done(response => {
// setLoading(false);
})
.fail(response => {
console.log('failed')
apiCallFailedRef.current = true;
timeout = setTimeout(() => callApi(), 28000);
});
}
};
// How would I clear the timeout correctly?
return () => {
clearTimeout(timeout);
};
}, [progress])
Upvotes: 0