Skip to content

useInterval

useInterval runs a body on a repeat for as long as the component exists and the body is a function.

useInterval(body: TimerBody, options?: { everyMs: Int }, on?: Ref): Timer
src/boost.ts2
const tick = useInterval(paused === 1 ? undefined : () => {
if (left === 0) {
tick.stop();
} else {
setLeft(left - 1);
}
}, { everyMs: 1000 });
  • body: A function taking no arguments, or undefined on the arm of a conditional that should clear the timer rather than set one.
  • options.everyMs: A number of milliseconds between runs. Left off, the body runs every client cycle.
  • on: A ref naming the component the timer lives on — its host. Defaults to this component’s root.

A Timer with one method:

  • stop(): Stops it. Safe to call from inside the body itself.
  • The phase is global, not measured from when the component appeared. “Every 1000 ms” means on the second, so several components on one period tick together, and the first tick lands on the next multiple of the period. For “1000 ms from now”, use useDelay.
  • It survives a rebuild of its component.
  • A timer that should end has to end itself. Nothing stops it for you.
  • One timer per host (TS2E213). Name a different host with the third argument, or split the component.
  • A hidden host does not tick. A timer under a hide does not tick, and picks up where it left when shown; a host 0 wide or 0 tall never ticks at all (TS2E252). See Timers.
  • A tick lands at or after the time asked for, within about 20 milliseconds.
  • A .map() row cannot call a hook (TS2E203). For a timer on each row, make the row a component: {ROWS.map((r, i) => <Row r={r} y={i * 16} />)}.
refused/use-interval.ts2
useInterval(() => { setSeconds(seconds + 1); }, { everyMs: 1000 });
useInterval(() => { setBlink(1 - blink); }, { everyMs: 500 }); // the timer is taken
src/boost.ts2
const [left, setLeft] = useState(60);
const [paused, setPaused] = useState(0);
const tick = useInterval(paused === 1 ? undefined : () => {
if (left === 0) {
tick.stop();
} else {
setLeft(left - 1);
}
}, { everyMs: 1000 });

While paused is 1 the body is undefined, which clears the timer.

src/boost.ts2
<layer x="right" y={2} w={56} h={18} onClick={() => { setPaused(1 - paused); }}>
src/deaf.ts2
useInterval(() => { setTicks(ticks + 1); }, { everyMs: 200 }, host);
src/deaf.ts2
<layer ref={host} w="fill" h="fill">

The phase is global, so the first tick lands at the next multiple of the period rather than a full period after the component appeared. Use useDelay if that matters.

The timer keeps running after I expected it to stop

Section titled “The timer keeps running after I expected it to stop”

Call tick.stop(), or make the body undefined on an arm. Reaching a condition does not stop a timer.

If it must keep counting while hidden, host it on a component that is not under the hide.

Two intervals on one host. Give the second a host of its own with the third argument, or move it into a component of its own.