React Timer Hook
react-timer-hook is a robust custom React hook library designed to simplify the implementation of timers, stopwatches, and general time-based logic within React components. It provides three core hooks: `useTimer` for countdowns, `useStopwatch` for count-up timers, and `useTime` for retrieving the current time. Currently stable at version `4.0.5`, the library maintains an active release cadence, frequently addressing bug fixes, dependency updates, and minor feature enhancements. A key differentiator is its out-of-the-box TypeScript support and its intelligent handling of browser tab inactivity to ensure accurate timer behavior, especially for stopwatches. It exposes a comprehensive set of time values including days, hours, minutes, seconds, milliseconds, and total raw seconds/milliseconds, along with functions for starting, pausing, resuming, and restarting timers, offering fine-grained control for various time-sensitive UI/UX requirements.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'setSeconds') at MyTimer
cause This error typically occurs when the `expiryTimestamp` prop passed to `useTimer` is `undefined` or not a valid `Date` object, leading to failed attempts to call Date methods.fixEnsure `expiryTimestamp` is always a valid `Date` object initialized with a future time, e.g., `new Date(Date.now() + 5 * 60 * 1000)` for a 5-minute timer. -
Property 'useTimer' does not exist on type 'typeof import("react-timer-hook")'.cause This TypeScript error indicates that type definitions are not being recognized, or you're attempting to use a default import instead of a named import for `useTimer`.fixVerify that you are using named imports (`import { useTimer } from 'react-timer-hook';`). If the issue persists, ensure `react-timer-hook@4.0.2` or newer is installed and your `tsconfig.json` correctly includes `node_modules/@types`. -
Timer is not accurate or stops when browser tab is inactive.
cause This was a known bug in `react-timer-hook` versions older than `3.0.4`, especially for `useStopwatch`, where browser throttling of background tabs affected timer precision.fixUpgrade your `react-timer-hook` package to version `3.0.4` or higher. This version contains the necessary fix for improved accuracy in inactive browser tabs. -
SyntaxError: Named export 'useTimer' not found. The requested module 'react-timer-hook' does not provide an export named 'useTimer'
cause This error usually arises from attempting to `require` an ES Module named export in a CommonJS environment, or incorrect module resolution setup in your build pipeline.fixAdopt the ES Module import syntax: `import { useTimer } from 'react-timer-hook';`. If you are strictly in a CommonJS environment, confirm your transpilation setup (e.g., Babel, Webpack) is correctly configured for ES module interop.
Warnings
- breaking Version 4.0.0 introduced support for milliseconds in the `useTimer` and `useStopwatch` hooks. While not strictly a breaking API change for existing users, applications relying solely on `seconds` as the smallest unit might need to adjust their display logic or `interval` setting if they intend to leverage or avoid millisecond precision.
- gotcha Prior to v4.0.2, TypeScript definition files were not consistently included in the distributed package. This caused compilation errors for TypeScript users attempting to import and use the library's hooks and types.
- gotcha Older versions of `useStopwatch` (prior to v3.0.4) experienced inaccuracies in timing when the browser tab was inactive. This was due to browser throttling of `setTimeout` and `setInterval` in background tabs, leading to incorrect stopwatch readings upon returning to the tab.
- gotcha The `expiryTimestamp` prop for `useTimer` is mandatory and must be a valid `Date` object representing a future point in time. Providing an invalid or `undefined` value will cause the timer to behave unexpectedly or throw runtime errors.
Install
-
npm install react-timer-hook -
yarn add react-timer-hook -
pnpm add react-timer-hook
Imports
- useTimer
import useTimer from 'react-timer-hook';
import { useTimer } from 'react-timer-hook'; - useStopwatch
const { useStopwatch } = require('react-timer-hook');import { useStopwatch } from 'react-timer-hook'; - useTime
import { UseTime } from 'react-timer-hook';import { useTime } from 'react-timer-hook'; - TimerControls
import type { TimerControls } from 'react-timer-hook';
Quickstart
import React from 'react';
import { useTimer } from 'react-timer-hook';
interface MyTimerProps {
expiryTimestamp: Date;
}
function MyTimer({ expiryTimestamp }: MyTimerProps) {
const {
totalSeconds,
milliseconds,
seconds,
minutes,
hours,
days,
isRunning,
start,
pause,
resume,
restart,
} = useTimer({ expiryTimestamp, onExpire: () => console.warn('onExpire called'), interval: 20 });
return (
<div style={{textAlign: 'center'}}>
<h1>react-timer-hook </h1>
<p>Timer Demo</p>
<div style={{fontSize: '100px'}}>
<span>{days}</span>:<span>{hours}</span>:<span>{minutes}</span>:<span>{seconds}</span>:<span>{milliseconds}</span>
</div>
<p>{isRunning ? 'Running' : 'Not running'}</p>
<button onClick={start}>Start</button>
<button onClick={pause}>Pause</button>
<button onClick={resume}>Resume</button>
<button onClick={() => {
const time = new Date();
time.setSeconds(time.getSeconds() + 300); // Set for 5 minutes from now
restart(time);
}}>Restart 5min</button>
</div>
);
}
export default function App() {
const time = new Date();
time.setSeconds(time.getSeconds() + 600); // 10 minutes timer
return (
<div>
<MyTimer expiryTimestamp={time} />
</div>
);
}