Wywoływanie rekurencyjne funkcji w React-cie z wykorzystaniem „setTimeout” i odwoływanie się w nich do stanów jest dość problematyczne. Taka funkcja „widzi zamrożony stan” pomimo tego, że może go zmieniać.
Poniżej sposób na timer (wykonywanie akcji z opóźnieniem) z możliwością dostępu do stanów w komponencie Reacta.
const [timerCounter, setTimerCounter] = useState(0);
useEffect(() => {
const id = setTimeout(
() => setTimerCounter(timerCounter + 1),
1000
);
console.log("TIK", timerCounter);
return () => clearTimeout(id);
}, [timerCounter]);
Przykład heartbeat-a odpytującego API
const [doReloadTime, setDoReloadTime] = useState(1000);
const [fetchState, setFetchState] =
useState<string>("waiting");
// aktualizacja danych
const onData = useCallback((data: any) => {
// ...
}, []);
// pobieranie danych z API
const reloadData = useCallback(() => {
setFetchState("waiting");
fetch(...)
.then(res => {
onData(res);
setFetchState("done");
setDoReloadTime(1000);
})
.catch(err => {
onData(null);
setFetchState("error");
setDoReloadTime(5000);
});
}, [onData]);
// heartbeat
useEffect(() => {
if (!reloadData || doReloadTime <= 0)
return;
setTimeout(() => {
reloadData();
}, doReloadTime);
setDoReloadTime(0);
}, [doReloadTime, reloadData]);