useTimer
function useTimer(options?: UseTimerOptions): TimerSnapshot & TimerControls;
Options
type UseTimerOptions = {
autoStart?: boolean;
updateIntervalMs?: number;
endWhen?: (snapshot: TimerSnapshot) => boolean;
onEnd?: (snapshot: TimerSnapshot, controls: TimerControls) => void | Promise<void>;
onError?: (error: unknown, snapshot: TimerSnapshot, controls: TimerControls) => void;
};
updateIntervalMs defaults to 1000 and must be positive and finite.
endWhen ends the lifecycle when it returns true.
onEnd fires once per generation. restart() creates a new generation.
onError receives sync throws and async rejections from onEnd.
The root useTimer() export is lifecycle-only to keep the default bundle small. Use @crup/react-timer-hook/schedules when you need polling schedules and schedule timing context.
Controls
type TimerControls = {
start(): void;
pause(): void;
resume(): void;
reset(options?: { autoStart?: boolean }): void;
restart(): void;
cancel(reason?: string): void;
};
cancel(reason) is a terminal early stop and does not call onEnd.
Snapshot
type TimerSnapshot = {
status: 'idle' | 'running' | 'paused' | 'ended' | 'cancelled';
now: number;
tick: number;
startedAt: number | null;
pausedAt: number | null;
endedAt: number | null;
cancelledAt: number | null;
cancelReason: string | null;
elapsedMilliseconds: number;
isIdle: boolean;
isRunning: boolean;
isPaused: boolean;
isEnded: boolean;
isCancelled: boolean;
};
Use now for wall-clock math. Use elapsedMilliseconds for active elapsed duration.