Skip to main content

Composition guide

Import map

PieceImportUse when
Core@crup/react-timer-hookOne lifecycle: stopwatch, countdown, clock, manual controls.
Duration@crup/react-timer-hook/durationDisplay days, hours, minutes, seconds, and milliseconds.
Schedules@crup/react-timer-hook/schedulesPolling, heartbeat checks, cadence callbacks, timing context.
Timer group@crup/react-timer-hook/groupMany keyed timers with independent lifecycle state.
Diagnostics@crup/react-timer-hook/diagnosticsOptional event logging while investigating behavior.

Core + duration

import { useTimer } from '@crup/react-timer-hook';
import { durationParts } from '@crup/react-timer-hook/duration';

const timer = useTimer({ autoStart: true, updateIntervalMs: 1000 });
const remaining = durationParts(Math.max(0, expiresAt - timer.now));

Schedules + diagnostics

import { consoleTimerDiagnostics } from '@crup/react-timer-hook/diagnostics';
import { useScheduledTimer } from '@crup/react-timer-hook/schedules';

const timer = useScheduledTimer({
autoStart: true,
diagnostics: consoleTimerDiagnostics({ label: 'auction' }),
schedules: [{ id: 'poll', everyMs: 5000, callback: pollAuction }],
});

Timer group + per-item schedules

import { useTimerGroup } from '@crup/react-timer-hook/group';

const timers = useTimerGroup({
items: jobs.map(job => ({
id: job.id,
autoStart: true,
schedules: [{ id: 'status', everyMs: 5000, callback: () => refreshJob(job.id) }],
})),
});

Display-only lists

If every row is just a countdown label, use one core timer and derive every row.

const clock = useTimer({ autoStart: true, updateIntervalMs: 1000 });

return auctions.map(auction => {
const remainingMs = Math.max(0, auction.expiresAt - clock.now);
return <AuctionRow key={auction.id} remainingMs={remainingMs} />;
});

Use useTimerGroup() only when rows need independent pause/resume/cancel/restart, onEnd, or per-item schedules.