Typed HooksGetting StarteduseInterval

useInterval

A custom hook for managing intervals in React projects.

useInterval is a powerful custom React hook that provides a declarative way to use intervals in React applications. Unlike the native setInterval, this hook properly handles component lifecycle, cleanup, and provides manual control over the interval execution.

This hook is particularly useful for scenarios like periodic data fetching, animations, timers, counters, or any situation where you need to execute a function repeatedly at specified intervals with proper React lifecycle management.

Idle
0

Interval Speed

1.0s

API

useInterval (callback: Callback, delay: Delay, options?: { autoStart?: boolean }): { stop: () => void, start: () => void, reset: () => void, isRunning`: boolean }

Parameters

ParameterTypeDescription
callbackCallbackThe function to be executed at each interval.
delayDelayThe delay in milliseconds for the interval. If null, the interval is paused and cleared.
optionsObject (optional)Configuration options with properties:
- autoStart (boolean, default: true): Whether the interval should start automatically.

Returns

  • Returns (Object): An object containing:
    • stop (() => void): Function to manually stop the interval.
    • start (() => void): Function to manually start the interval.
    • reset (() => void): Function to reset the interval (stop and potentially restart).
    • isRunning (boolean): Boolean indicating if the interval is currently running.

Hook

import { useEffect, useRef, useState, useCallback } from 'react'
 
/**
 * A custom hook that sets up an interval and executes a callback function at the specified delay.
 * It also provides functions to manually start/stop the interval and check if it's running.
 *
 * @param callback - The function to be executed at each interval.
 * @param delay - The delay in milliseconds for the interval. If `null`, the interval is paused and cleared.
 * @returns An object containing `stop`, `start` functions and `isRunning` state.
 *
 * @example
 * const { stop, start, isRunning } = useInterval(() => {
 *   console.log("This will run every second");
 * }, 1000);
 *
 * To pause the interval:
 * const { stop, start, isRunning } = useInterval(() => {
 *   console.log("This will not run");
 * }, null);
 *
 * To stop/start the interval manually:
 * stop(); // stops the interval
 * start(); // starts the interval again
 */
 
type Callback = () => void
type Delay = number | null
type UseInterval = (
  callback: Callback,
  delay: Delay,
  options?: { autoStart?: boolean }
) => {
  stop: () => void
  start: () => void
  reset: () => void
  isRunning: boolean
}
 
export const useInterval: UseInterval = (callback, delay, options = {}) => {
  const { autoStart = true } = options
  const savedCallback = useRef<Callback>(callback)
  const intervalId = useRef<ReturnType<typeof setInterval> | null>(null)
  const [isRunning, setIsRunning] = useState(false)
 
  // Remember the latest callback if it changes.
  useEffect(() => {
    savedCallback.current = callback
  }, [callback])
 
  /** Reusable function to clear interval */
  const clearCurrentInterval = useCallback(() => {
    if (intervalId.current) {
      clearInterval(intervalId.current)
      intervalId.current = null
      setIsRunning(false)
    }
  }, [])
 
  /** Reusable function to start interval */
  const startInterval = useCallback(() => {
    if (!intervalId.current && delay !== null) {
      intervalId.current = setInterval(() => {
        savedCallback.current()
      }, delay)
      setIsRunning(true)
    }
  }, [delay])
 
  useEffect(() => {
    /**
     * Don't schedule if no delay is specified.
     * Note: 0 is a valid value for delay.
     */
    if (delay === null) {
      clearCurrentInterval()
      return
    }
 
    if (autoStart) {
      startInterval()
    }
 
    return clearCurrentInterval
  }, [delay, autoStart, clearCurrentInterval, startInterval])
 
  /** Function to stop the interval manually. */
  const stop = clearCurrentInterval
 
  /** Function to start the interval manually. */
  const start = startInterval
 
  const reset = useCallback(() => {
    clearCurrentInterval()
    if (autoStart && delay !== null) {
      startInterval()
    }
  }, [clearCurrentInterval, startInterval, autoStart, delay])
 
  return {
    stop,
    start,
    reset,
    isRunning,
  }
}