React Timer Implementation §
Basic example §
export function Timer() {
const [isRunning, setIsRunning] = useState(false);
const [elapsedTime, setElapsedTime] = useState(0);
useEffect(() => {
let intervalId: NodeJS.Timeout;
if (isRunning) {
intervalId = setInterval(() => {
setElapsedTime((prev) => {
const newTime = prev + 1;
return newTime;
});
}, 1000);
}
return () => {
if (intervalId) {
clearInterval(intervalId);
}
};
}, [isRunning, onDurationChange]);
const toggleTimer = () => {
setIsRunning(!isRunning);
};
return (...);
}
Take inactive tab into consideration §
export function Timer() {
const [isRunning, setIsRunning] = useState(false);
const [elapsedTime, setElapsedTime] = useState(0);
const [startTime, setStartTime] = useState<number | null>(null);
useEffect(() => {
let intervalId: NodeJS.Timeout;
const handleVisibilityChange = () => {
if (document.hidden) {
if (intervalId) {
clearInterval(intervalId);
}
} else if (isRunning && startTime) {
const now = Date.now();
const timeDiff = Math.floor((now - startTime) / 1000);
setElapsedTime(timeDiff);
}
};
if (isRunning) {
setStartTime(startTime || Date.now() - elapsedTime * 1000);
intervalId = setInterval(() => {
const now = Date.now();
if (startTime) {
const timeDiff = Math.floor((now - startTime) / 1000);
setElapsedTime(timeDiff);
}
}, 1000);
document.addEventListener("visibilitychange", handleVisibilityChange);
}
return () => {
if (intervalId) {
clearInterval(intervalId);
}
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, [isRunning, startTime, elapsedTime]);
const toggleTimer = () => {
if (!isRunning) {
setStartTime(Date.now() - elapsedTime * 1000);
} else {
setStartTime(null);
}
setIsRunning(!isRunning);
};
return (...);
}
Reference §