useTimer
React hook to create a timer functionality.
Add the hook via the CLI:
npx @novajslabs/cli add useTimer
npx @novajslabs/cli add useTimer
pnpm dlx @novajslabs/cli add useTimer
Or copy and paste the code into your project:
import { useState, useEffect } from "react";
const parseTime = (time: string) => {
const splitTime = time.split(":");
const [days, hours, minutes, seconds] = splitTime.map((value) =>
Number(value)
);
return { days, hours, minutes, seconds };
};
const addLeadingZero = (digit: number): string => {
let timeStr = "";
digit % 10 === digit ? (timeStr += `0${digit}`) : (timeStr += `${digit}`);
return timeStr;
};
interface Timer {
current: string;
isPaused: boolean;
isOver: boolean;
currentDays: number;
currentHours: number;
currentMinutes: number;
currentSeconds: number;
elapsedSeconds: number;
remainingSeconds: number;
pause: () => void;
play: () => void;
reset: () => void;
togglePause: () => void;
}
export const useTimer = (startTime: string): Timer => {
const { days, hours, minutes, seconds } = parseTime(startTime);
const [time, setTime] = useState({ days, hours, minutes, seconds });
const [paused, setPaused] = useState(false);
const divider = ":";
const [isOver, setIsOver] = useState(false);
useEffect(() => {
if (paused) {
return;
}
const interval = setInterval(() => {
setTime((prev) => {
let d = prev.days;
let h = prev.hours;
let m = prev.minutes;
let s = prev.seconds;
if (s - 1 < 0) {
s = 59;
if (m - 1 < 0) {
m = 59;
if (h - 1 < 0) {
h = 23;
if (d - 1 >= 0) {
d--;
}
} else {
h--;
}
} else {
m--;
}
} else {
s--;
}
return { days: d, hours: h, minutes: m, seconds: s };
});
}, 1000);
if (
time.seconds === 0 &&
time.minutes === 0 &&
time.hours === 0 &&
time.days === 0
) {
setIsOver(true);
clearInterval(interval);
return;
}
return () => clearInterval(interval);
}, [days, hours, minutes, seconds, time, paused]);
return {
current: `${addLeadingZero(time.days)}${divider}${addLeadingZero(
time.hours
)}${divider}${addLeadingZero(time.minutes)}${divider}${addLeadingZero(
time.seconds
)}`,
isPaused: paused,
isOver,
currentDays: time.days,
currentHours: time.hours,
currentMinutes: time.minutes,
currentSeconds: time.seconds,
elapsedSeconds:
days * 86400 +
hours * 3600 +
minutes * 60 +
seconds -
(time.days * 86400 +
time.hours * 3600 +
time.minutes * 60 +
time.seconds),
remainingSeconds:
time.days * 86400 + time.hours * 3600 + time.minutes * 60 + time.seconds,
pause: () => setPaused(true),
play: () => setPaused(false),
reset: () => {
setIsOver(false);
setTime({ days, hours, minutes, seconds });
},
togglePause: () => {
setPaused(!paused);
},
};
};
import { useState, useEffect } from "react";
const parseTime = (time) => {
const splitTime = time.split(":");
const [days, hours, minutes, seconds] = splitTime.map((value) =>
Number(value)
);
return { days, hours, minutes, seconds };
};
const addLeadingZero = (digit) => {
let timeStr = "";
digit % 10 === digit ? (timeStr += `0${digit}`) : (timeStr += `${digit}`);
return timeStr;
};
export const useTimer = (startTime) => {
const { days, hours, minutes, seconds } = parseTime(startTime);
const [time, setTime] = useState({ days, hours, minutes, seconds });
const [paused, setPaused] = useState(false);
const divider = ":";
const [isOver, setIsOver] = useState(false);
useEffect(() => {
if (paused) {
return;
}
const interval = setInterval(() => {
setTime((prev) => {
let d = prev.days;
let h = prev.hours;
let m = prev.minutes;
let s = prev.seconds;
if (s - 1 < 0) {
s = 59;
if (m - 1 < 0) {
m = 59;
if (h - 1 < 0) {
h = 23;
if (d - 1 >= 0) {
d--;
}
} else {
h--;
}
} else {
m--;
}
} else {
s--;
}
return { days: d, hours: h, minutes: m, seconds: s };
});
}, 1000);
if (
time.seconds === 0 &&
time.minutes === 0 &&
time.hours === 0 &&
time.days === 0
) {
setIsOver(true);
clearInterval(interval);
return;
}
return () => clearInterval(interval);
}, [days, hours, minutes, seconds, time, paused]);
return {
current: `${addLeadingZero(time.days)}${divider}${addLeadingZero(
time.hours
)}${divider}${addLeadingZero(time.minutes)}${divider}${addLeadingZero(
time.seconds
)}`,
isPaused: paused,
isOver,
currentDays: time.days,
currentHours: time.hours,
currentMinutes: time.minutes,
currentSeconds: time.seconds,
elapsedSeconds:
days * 86400 +
hours * 3600 +
minutes * 60 +
seconds -
(time.days * 86400 +
time.hours * 3600 +
time.minutes * 60 +
time.seconds),
remainingSeconds:
time.days * 86400 + time.hours * 3600 + time.minutes * 60 + time.seconds,
pause: () => setPaused(true),
play: () => setPaused(false),
reset: () => {
setIsOver(false);
setTime({ days, hours, minutes, seconds });
},
togglePause: () => {
setPaused(!paused);
},
};
};
Requirements
React 16.8 or higher
Parameters
startTime required
Type: string
Represents the initial value of the timer in the format dd:hh:mm:ss
.
Return values
current
Type: string
The current value of the timer.
isPaused
Type: boolean
Represents whether the timer is paused (true
) or not (false
).
isOver
Type: boolean
Represents whether the timer has ended (true
) or not (false
).
currentDays
Type: number
The current value of days on the timer.
currentHours
Type: number
The current value of hours on the timer.
currentMinutes
Type: number
The current value of minutes on the timer.
currentSeconds
Type: number
The current value of the seconds in the timer.
elapsedSeconds
Type: number
The number of seconds that have passed since the start of the timer.
remainingSeconds
Type: number
The number of seconds left until the timer ends.
pause
Type: function
Pause the timer.
play
Type: function
Play the timer.
reset
Type: function
Reset the timer.
togglePause
Type: function
Toggle between pausing and playing the timer.
Example
import { useTimer } from "./hooks/useTimer";
const App = () => {
const {
current,
isPaused,
isOver,
currentDays,
currentHours,
currentMinutes,
currentSeconds,
elapsedSeconds,
remainingSeconds,
pause,
play,
reset,
togglePause,
} = useTimer("00:00:00:05");
return (
<div>
<p>Counter value: {current}</p>
<p>Is the counter paused? {isPaused ? "Yes" : "No"}</p>
<p>Has the counter over? {isOver ? "Yes" : "No"}</p>
<p>Current days: {currentDays}</p>
<p>Current hours: {currentHours}</p>
<p>Current minutes: {currentMinutes}</p>
<p>Current seconds: {currentSeconds}</p>
<p>Elapsed seconds: {elapsedSeconds}</p>
<p>Remaining seconds: {remainingSeconds}</p>
<button onClick={pause}>Pause</button>
<button onClick={play}>Play</button>
<button onClick={reset}>Reset</button>
<button onClick={togglePause}>Toggle Pause</button>
</div>
);
};
export default App;
Use cases
Here are some use cases where this React hook is useful:
- Implementing a countdown timer for a time-limited quiz or exam in an online learning platform
- Creating a countdown clock for tracking time-sensitive tasks or deadlines in a project management tool
- Developing a timer feature for timing cooking recipes or workouts in a fitness app
- Adding a countdown timer for promotions or special events in an e-commerce website
- Integrating a timer functionality for time-bound challenges or activities in a gamified learning platform