Feedback
useTimer
A countdown timer that keeps time by the clock, not by ticks, so it stays right in a background tab, across a reload (with timerId) and when the screen sleeps. It re-renders four times a second while it runs, and calls onDone once at zero. Every useTimer, Timer and TimerTray with the same timerId shares one timer, in this tab and in others.
import { useTimer } from "@/lib/ouro/use-timer";Example
const timer = useTimer({ duration: 600, timerId: "pasta", onDone: () => chime() });
<Button onClick={timer.start}>Start</Button>
<p>{formatDuration(timer.remaining)}</p>Use instead when
- Use
Timerinstead for the whole control (the time, Start, Pause and the alert), and this hook for a timer of your own design.
Parameters
{ duration, timerId, onDone, fallback }- Type:
TimerOptions
Returns
TimerControls
Types
TimerControls
What useTimer returns.
interface TimerControls {
status: TimerStatus;
/**
* Whole seconds left, rounded up: the full duration before it starts, 0 once it is done.
*/
remaining: number;
/** The timer's length in seconds, as it was started. */
duration: number;
/**
* When it reached zero, or `null` until it does.
*/
endedAt: number | null;
/** Starts from the full duration, from any status. */
start: () => void;
/** Stops a running timer where it is. */
pause: () => void;
/** Carries a paused timer on from where it stopped. */
resume: () => void;
/** Cancels or dismisses the timer: back to `idle` at the full duration, and forgotten. */
reset: () => void;
}TimerDoneEvent
What a timer's onDone hears when it reaches zero.
interface TimerDoneEvent {
/**
* When it reached zero, in milliseconds since the epoch: in the past when the page was closed at the time.
*/
endedAt: number;
/**
* Whether this `useTimer` is the one on the page that should sound the alert: the first with
* the timer's `timerId` to hear it, not counting `fallback` ones unless only those are mounted. When
* a `Timer` and a `TimerTray` both show one timer, the `Timer` alerts, whichever mounted first.
* A hook without `onDone` reads the timer without taking the alert.
*/
first: boolean;
}TimerOptions
Options for useTimer.
interface TimerOptions {
/** How long the timer runs, in seconds. */
duration: number;
/**
* Keeps the timer in `localStorage` under this name, so it carries on through a reload and
* a closed tab, and shares it with every `useTimer`, `Timer` and `TimerTray` given the same
* `timerId`, in this tab and in others. Without it the timer lives as long as the component.
*/
timerId?: string | undefined;
/** Not an option. A timer is kept and shared by `timerId`: `useTimer({ duration: 600, timerId: "pasta" })`. */
id?: { 'Use timerId: "pasta"': never };
/**
* Called once when the timer reaches zero, including when it ended while the page was closed.
*/
onDone?: ((event: TimerDoneEvent) => void) | undefined;
/**
* For a view that watches a timer shown elsewhere, as `TimerTray` does: its `onDone` hears
* `first: true` only while no `useTimer` without `fallback` shares the timer.
*/
fallback?: boolean | undefined;
}TimerStatus
Where a timer is: not started, counting down, stopped part way, or at zero.
type TimerStatus = "idle" | "running" | "paused" | "done";