Chizi Victor

_   Snippets

May 29, 2025

useCountdown hook

Manage countdown state with configurable start/end times.

A React hook that creates a customizable countdown timer which counts down from an initial value to a target value at a specified interval, providing the current count and a reset function.

import { useEffect, useRef, useState } from "react";

interface CountdownOptions {
  initialSeconds?: number;
  interval?: number;

  /** @throws if targetSeconds >= initialSeconds */
  targetSeconds?: number;
}

/**
 * Custom hook for creating a countdown timer.
 *
 * @param initialSeconds - The number of seconds to count down from (defaults to 60)
 * @param interval - The interval in milliseconds between each countdown tick (defaults to 100ms)
 * @param targetSeconds - The number of seconds to count down to (defaults to 0)
 *
 * @returns An object containing:
 *  - count: The current count in seconds (as a number)
 *  - reset: A function to reset the countdown to the initial value
 */
export function useCountdown({
  initialSeconds = 60,
  interval = 100,
  targetSeconds = 0,
}: CountdownOptions = {}) {
  const intervalRef = useRef<NodeJS.Timeout>(undefined);

  const MS = 1000;
  const initialCount = initialSeconds * MS;
  const target = targetSeconds * MS;

  const [count, setCount] = useState(initialCount);

  const formattedCount = (count / MS).toFixed();

  useEffect(() => {
    intervalRef.current = createTimeout();

    return () => {
      clearInterval(intervalRef.current);
    };
  }, [intervalRef.current]);

  function createTimeout() {
    return setInterval(() => {
      setCount((prev) => {
        if (prev <= target) {
          clearInterval(intervalRef.current);
          return prev;
        }

        return prev - 100;
      });
    }, interval);
  }

  function reset() {
    setCount(initialCount);
    intervalRef.current = createTimeout();
  }

  return { count: Number(formattedCount), reset };
}

Basic usage with default values (60 seconds countdown)

const { count, reset } = useCountdown();

Custom configuration example

const { count, reset } = useCountdown({
  initialSeconds: 30, // Start from 30 seconds
  interval: 500, // Update every 500ms
  targetSeconds: 5, // Stop at 5 seconds
});