A flexible, high-performance, and type-safe countdown timer hook for React applications. This hook provides precise time tracking, support for fractional intervals (milliseconds), and built-in methods for game mechanics (bonus/penalty time) and progress tracking.
This hook is currently available as a standalone utility. You can use it by directly adding the source file to your project.
- Create a new file named
useTimer.tsin your project's hooks directory (e.g.,src/hooks/useTimer.ts). - Copy the full code from the
useTimer.tsfile in this repository. - Paste it into your newly created file.
Once the file is created, import it into your components like any other hook:
import useTimer from './hooks/useTimer';- Type-Safe: Written in TypeScript with full type definitions.
- Performance Optimized: Uses
useRefto prevent unnecessary re-renders and closure staleness. - Flexible Steps: Supports standard second-by-second countdowns or millisecond precision (e.g., 0.1s steps).
- Progress Tracking: Returns a calculated progress percentage automatically.
- Time Manipulation: Includes
adjustTimefor dynamic time addition/subtraction (ideal for quizzes or games). - Auto-start: Optional configuration to start immediately upon mounting.
A simple 60-second timer that displays the remaining time.
const BasicTimer = () => {
const { timeLeft, isRunning, startTimer, stopTimer, resetTimer } = useTimer({
initialTime: 60,
onTimeOver: () => console.log('Timer finished!'),
});
return (
<div>
<p>Time Remaining: {timeLeft}</p>
<button onClick={startTimer} disabled={isRunning}>Start</button>
<button onClick={stopTimer} disabled={!isRunning}>Stop</button>
<button onClick={resetTimer}>Reset</button>
</div>
);
};Example of a Pomodoro-style timer using the progress return value and onTick callback.
const PomodoroTimer = () => {
const { timeLeft, progress } = useTimer({
initialTime: 1500, // 25 minutes
autoStart: true,
onTick: (time) => {
if (time === 60) console.log('1 minute warning!');
},
onTimeOver: () => alert('Session Complete'),
});
const formatTime = (seconds: number) => {
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return `${m}:${s < 10 ? '0' : ''}${s}`;
};
return (
<div>
<div style={{ width: '100%', height: '10px', background: '#eee' }}>
<div style={{ width: `${progress}%`, height: '100%', background: 'blue' }} />
</div>
<h2>{formatTime(timeLeft)}</h2>
</div>
);
};Using adjustTime and step for high-frequency updates and game logic.
const GameTimer = () => {
const { timeLeft, adjustTime, startTimer } = useTimer({
initialTime: 30,
step: 0.1, // Update every 100ms
onTimeOver: () => alert('Game Over'),
});
return (
<div>
<h3>Time: {timeLeft.toFixed(1)}</h3>
<button onClick={startTimer}>Start Game</button>
<button onClick={() => adjustTime(5)}>Bonus (+5s)</button>
<button onClick={() => adjustTime(-3)}>Penalty (-3s)</button>
</div>
);
};Pass these options to the useTimer hook:
| Prop | Type | Default | Description |
|---|---|---|---|
initialTime |
number |
Required | The starting time in seconds. |
onTimeOver |
() => void |
undefined |
Callback fired when the timer reaches 0. |
onTick |
(time: number) => void |
undefined |
Callback fired on every interval step. Receives current time. |
autoStart |
boolean |
false |
If true, the timer starts immediately on mount. |
step |
number |
1 |
The interval in seconds to count down by. Use decimals (e.g., 0.1) for faster ticks. |
The hook returns an object containing the following:
| Name | Type | Description |
|---|---|---|
timeLeft |
number |
The current remaining time in seconds. |
isRunning |
boolean |
true if the timer is currently active. |
progress |
number |
The percentage of time remaining (0-100) relative to initialTime. |
startTimer |
() => void |
Starts or resumes the timer. |
stopTimer |
() => void |
Pauses the timer without resetting. |
resetTimer |
() => void |
Stops the timer and resets timeLeft to initialTime. |
adjustTime |
(amount: number) => void |
Adds (positive) or removes (negative) time. Will not go below 0. |
setTime |
(time: number) => void |
Manually sets the timer to a specific value. |
This software is provided "as is", without warranty of any kind, express or implied. While this hook has been optimized for performance and type safety, please ensure it meets the specific requirements of your project before deploying to production.
MIT