As Vasanth mention, I preferred to:
import { useEffect, useRef } from 'react';
export const useInterval = (
callback: Function,
fnCondition: Function,
delay: number,
) => {
const savedCallback = useRef<Function>();
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
let id: NodeJS.Timeout;
const tick = async () => {
try {
const response =
typeof savedCallback.current === 'function' &&
(await savedCallback.current());
if (fnCondition(response)) {
id = setTimeout(tick, delay);
} else {
clearTimeout(id);
}
} catch (e) {
console.error(e);
}
};
tick();
return () => id && clearTimeout(id);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [delay]);
};
WORKS: Using fnCondition inside which can be a condition based on the response from the last request.
//axios-hooks
const {
data,
isLoadingData,
getData,
} = api.useGetData();
const fnCondition = (result: any) => {
const randomContidion = Math.random();
//return true to continue
return randomContidion < 0.9;
};
useInterval(() => getData(), fnCondition, 1000);
DOES NOT WORK: Passing delay as null to stop useInterval like this does not work for me
with this code: https://www.aaron-powell.com/posts/2019-09-23-recursive-settimeout-with-react-hooks/
(You might get the impression it works, but after a few starts/stops it breaks)
const [isRunning, setIsRunning] = useState(true);
const handleOnclick = () => {
setIsRunning(!isRunning);
};
useInterval(() => getData(), isRunning ? 1000 : null);
<button onClick={handleOnclick}>{isRunning ? 'Stop' : 'Start'}</button>
Sum up: I'm able to stop useInterval by passing fnCondition, but not by passing delay=null