@supunlakmal/hooks
Version:
A collection of reusable React hooks
68 lines • 2.75 kB
JavaScript
import { useState, useEffect, useCallback, useRef } from 'react';
/**
* Manages a countdown timer with start, pause, and reset controls.
*
* @param options Configuration options for the countdown timer.
* @returns Controls and state for the countdown timer.
*/
export const useCountdown = ({ seconds, interval = 1000, onComplete, autoStart = true, }) => {
const [remainingSeconds, setRemainingSeconds] = useState(seconds);
const [isRunning, setIsRunning] = useState(autoStart);
const intervalRef = useRef(null);
const onCompleteRef = useRef(onComplete);
useEffect(() => {
onCompleteRef.current = onComplete;
}, [onComplete]);
const clearExistingInterval = useCallback(() => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}, []);
const tick = useCallback(() => {
setRemainingSeconds((prevSeconds) => {
var _a;
// Use interval seconds calculation instead of decrementing by 1
const secondsToDecrement = interval / 1000;
if (prevSeconds <= secondsToDecrement) {
clearExistingInterval();
setIsRunning(false);
(_a = onCompleteRef.current) === null || _a === void 0 ? void 0 : _a.call(onCompleteRef);
return 0;
}
return prevSeconds - secondsToDecrement;
});
}, [interval, clearExistingInterval]);
useEffect(() => {
if (isRunning && remainingSeconds > 0) {
intervalRef.current = setInterval(tick, interval);
}
else {
clearExistingInterval();
}
return clearExistingInterval; // Cleanup interval on unmount or when isRunning/interval changes
}, [isRunning, interval, tick, remainingSeconds, clearExistingInterval]);
const start = useCallback(() => {
if (!isRunning && remainingSeconds > 0) {
setIsRunning(true);
}
}, [isRunning, remainingSeconds]);
const pause = useCallback(() => {
if (isRunning) {
setIsRunning(false);
}
}, [isRunning]);
const reset = useCallback(() => {
clearExistingInterval();
setRemainingSeconds(seconds);
setIsRunning(autoStart);
}, [seconds, autoStart, clearExistingInterval]);
// Effect to handle changes in the initial seconds prop
useEffect(() => {
setRemainingSeconds(seconds);
// Optionally restart timer if it was running
// setIsRunning(autoStart); // Decided against auto-restart on prop change
}, [seconds]);
return { remainingSeconds, isRunning, start, pause, reset };
};
//# sourceMappingURL=useCountdown.js.map