Use cases
Start with the root hook, then add a subpath only when the screen needs it.
| Need | Use | Import | Live recipe |
|---|---|---|---|
| Stopwatch, clock, absolute deadline, pausable countdown | Core | @crup/react-timer-hook | Stopwatch |
| OTP resend, retry button, invite cooldown | Core + duration | @crup/react-timer-hook + /duration | OTP resend cooldown |
| Human display parts like days/minutes/seconds | Core + duration | @crup/react-timer-hook + /duration | Pausable countdown |
| Polling or cadence callbacks while a timer is active | Schedules | @crup/react-timer-hook/schedules | Polling schedule |
| Draft autosave or presence heartbeat | Schedules | @crup/react-timer-hook/schedules | Autosave heartbeat |
| Polling that can stop the lifecycle early | Schedules | @crup/react-timer-hook/schedules | Poll and cancel |
| Dozens of rows with independent pause/resume/cancel | Timer group | @crup/react-timer-hook/group | Timer group |
| Checkout or reservation holds | Timer group | @crup/react-timer-hook/group | Checkout holds |
| Per-row polling or status checks | Timer group + schedules | @crup/react-timer-hook/group | Per-item polling |
| Runtime add/update/remove of timer items | Timer group | @crup/react-timer-hook/group | Dynamic items |
| Toast or snackbar auto-dismiss | Timer group | @crup/react-timer-hook/group | Toast auto-dismiss |
| Development event tracing | Diagnostics | @crup/react-timer-hook/diagnostics | Diagnostics |
Real-world mapping
| Product case | Composition | Why |
|---|---|---|
| Auction card countdown | Core | One server deadline, derived from timer.now. |
| Auction list with pause/resume per lot | Timer group | Each row owns lifecycle state and controls. |
| Auction status polling | Schedules or group schedules | Poll cadence is separate from UI update cadence. |
| Checkout reservation hold | Core + duration | Pausable duration math and friendly display parts. |
| OTP resend button | Core + duration | Short local cooldown with a disabled/enabled button state. |
| Seat map with many expiring holds | Timer group | Many keyed holds, one scheduler. |
| Draft editor autosave | Schedules | A running lifecycle owns the autosave cadence and errors. |
| Upload/job dashboard | Timer group + schedules | Rows can poll status and end independently. |
| Focus/break timer | Core + duration | Pausable countdown based on active elapsed time. |
| Live clock widget | Core | Derive new Date(timer.now). |
| Toast expiry with pause-on-hover | Timer group | Each toast can pause, resume, cancel, and remove. |
Rule of thumb
Use one useTimer() for display-only lists when every row can derive from the same now.
Use useTimerGroup() when rows need independent state, controls, schedules, or callbacks.
Use useScheduledTimer() when the timer itself owns cadence callbacks such as polling, heartbeat checks, or autosave pings.