When building a countdown timer in React with Hooks, the most common mistakes are:

  1. Placing setInterval outside of useEffect (causes multiple intervals/flickering).
  2. Not clearing intervals properly (memory leaks, multiple timers running).
  3. Calculating time incorrectly (restarting on every render).

Here’s a clean, optimized implementation of a countdown timer using useEffect and useState:

import React, { useEffect, useState } from "react";
const Timer = ({ initialSeconds = 300 }) => {
 const [timeLeft, setTimeLeft] = useState(initialSeconds);
  useEffect(() => {
    if (timeLeft <= 0) return; // stop when timer reaches 0

    const intervalId = setInterval(() => {
      setTimeLeft(prev => {
        if (prev <= 1) {
          clearInterval(intervalId); // cleanup when reaching 0
          return 0;
        }
        return prev - 1;
      });
    }, 1000);

    // cleanup interval when component unmounts or updates
    return () => clearInterval(intervalId);
  }, [timeLeft]);

  // format mm:ss
  const formatTime = seconds => {
    const minutes = String(Math.floor(seconds / 60)).padStart(2, "0");
    const secs = String(seconds % 60).padStart(2, "0");
    return `${minutes}:${secs}`;
  };

  return (
    <div>
      <h1>{formatTime(timeLeft)}</h1>
    </div>
  );
};

export default Timer;

 

Code Understanding

  1. useEffect ensures the interval starts only when needed and cleans up properly.
  2. We decrement based on previous state (prev – 1) instead of recalculating from scratch each time.
  3. Timer stops automatically when reaching 0.
  4. formatTime ensures output is always mm:ss (e.g., 02:05).
Also Read

Also Read:

React Security

Need Help With React Development?

Work with our skilled React developers to accelerate your project and boost its performance.

Hire Reactjs Developers

Support On Demand!

Related Q&A