useIntervalLoading saved progress…

useInterval

Build a declarative wrapper around setInterval for React. Raw setInterval is imperative and clashes with React's render model — you have to set it up, tear it down, and somehow keep its callback from going stale. useInterval(callback, delay) hides all of that: it runs callback every delay milliseconds, always calls the latest version of the callback, pauses when delay is null, and cleans itself up on unmount. This is the classic hook popularized by Dan Abramov's Making setInterval Declarative.

Signature

function useInterval(callback: () => void, delay: number | null): void;

Passing delay = null pauses the interval. The hook returns nothing.

Examples

function Clock() {
  const [count, setCount] = useState(0);
  const [running, setRunning] = useState(true);

  // Pausing is just passing null as the delay.
  useInterval(() => setCount((c) => c + 1), running ? 1000 : null);

  return (
    <div>
      <span>{count}</span>
      <button onClick={() => setRunning((r) => !r)}>
        {running ? 'pause' : 'resume'}
      </button>
    </div>
  );
}
// The interval always runs the LATEST callback, even after the component
// re-renders with a new one — no stale closures.
// delay = 100:  tick … tick … tick   (every 100ms)
// delay = null: (paused — no ticks)

Notes

  • null means paused. A numeric delay schedules the timer; null skips scheduling entirely. Toggling between them pauses and resumes.
  • The callback must never go stale. If the component re-renders with a new callback (a common case, since inline arrow functions are recreated every render), the next tick must call the new one — without restarting the timer.
  • Changing the delay restarts at the new rate. Going from 1000 to 500 should tear down the old timer and start a new one.
  • Clean up on unmount. The interval must stop when the component unmounts — no callbacks firing into a dead component.
Loading editor…