How to Set Up Countdown Timer in React

Irakli Tchigladze Feb 02, 2024
How to Set Up Countdown Timer in React

Modern web applications built in React often involve keeping track of time. For instance, if you have a blog, every post must show its date and how much time has passed since posting.

React applications can have a diverse set of features. Implementing a countdown timer in JavaScript can be pretty difficult. It involves manipulating date values or formatting them.

Let’s look at a sample implementation of a countdown in React application.

Implementation of Countdown Timer in React

In general, countdown timers in all React frameworks are structured the same way. Components are React applications’ main building blocks.

We’ll build a functional component for the countdown timer in this example. We will use hooks to maintain the state and manage side effects.

Use useState() and useEffect() Hooks to Set Up Countdown Timer in React

Functional React components can have different structures, but they all follow the same basic pattern. Let’s set up a function and call it Countdown.

Presumably, you will use this component within a parent component, so we should also accept props.

export default function Countdown(props){
    return (
    <div>
    {!(mins && secs) ? "" : (
        <p>
          {" "}
          {mins}:{secs < 10 ? `0${secs}` : secs}
        </p>
      )}    
    </div>
    )
}

So far, this is very simple. We’re going to get starting minutes and seconds values from the props. If there are no minutes and seconds to count down from, there’s no timer to display an empty string.

If the values are available, it’s better always to display seconds in double digits for formatting consistency, even if it’s a single-digit number. We achieve that by using the template literal within the curly braces.

As we can see, the mins and secs values are destructured, so our next step will be to do that. We also mentioned that we’re going to need useState() and useEffect() hooks. The former will be necessary to keep track of changing times.

If we were working with class components, we would use lifecycle methods to handle the change of time. We can use the useEffect() hooks for functional components with many lifecycle methods features.

So, without further ado, let’s introduce the hooks into our application:

import React from "react";
import { useState, useEffect } from "react";
export default function Countdown(props){
  const { startingMinutes = 0, startingSeconds = 0 } = props;
  const [mins, setMinutes] = useState(startingMinutes);
  const [secs, setSeconds] = useState(startingSeconds);
    return (
    <div>
    {!(mins && secs) ? "" : (
        <p>
          {" "}
          {mins}:{secs < 10 ? `0${secs}` : secs}
        </p>
      )}    
    </div>
    )
}

We have to start importing the useState and useEffect hooks from the core library.

So far, the mins and secs state variables are set to 0, so we’re not going to see anything on the screen. However, if you change the startingMinutes and startingSeconds values of the props, you’ll see a starting point of a countdown. In the code above, we also defined functions for updating the state.

The essence of a countdown is to deduct a certain time value periodically. For that, we’re going to need the setInterval() method. It executes a piece of code once every specified amount of time.

In this case, with every passing second, we must decrease the total seconds by 1. Once every 60 seconds, we must also decrease the starting minutes by 1.

Our finished application is going to look something like this:

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

export default function Countdown(props) {
  const { startingMinutes = 111, startingSeconds = 0 } = props;
  const [mins, setMinutes] = useState(startingMinutes);
  const [secs, setSeconds] = useState(startingSeconds);
  useEffect(() => {
    let sampleInterval = setInterval(() => {
      if (secs > 0) {
        setSeconds(secs - 1);
      }
      if (secs === 0) {
        if (mins === 0) {
          clearInterval(sampleInterval);
        } else {
          setMinutes(mins - 1);
          setSeconds(59);
        }
      }
    }, 1000);
    return () => {
      clearInterval(sampleInterval);
    };
  });

  return (
    <div>
      {!(mins && secs) ? "" : (
        <p>
          {" "}
          {mins}:{secs < 10 ? `0${secs}` : secs}
        </p>
      )}
    </div>
  );
}

There’s a lot to unpack here. First, let’s explain the logic of our setInterval() callback since this is the code that will be executed once every specified amount of time.

First, we check if the secs state value is more than 0, and if it is, we update the state with the secs - 1 value. It’s practically the core functionality of our countdown.

The next step defines what should happen if the secs and mins are 0. In this case, we cancel the repeated execution of the code by calling the clearInterval() function.

Finally, in the else statement, we handle the case when the seconds have reached 0, but there are still minutes to deduct.

The callback function is the first argument. It contains the piece of code that should execute repeatedly.

In our example, we wrote an inline function, but we could just as easily have written it separately and referenced it in our setInterval() method, like this:

setInterval(someFunction, 1000)

The second argument in that example, as well as the original sample, refers to delay. It specifies how much time the setInterval() function should wait between the executions of the code.

The time value is specified in milliseconds. In our example, we want the countdown timer to be executed every second, 1000 milliseconds.

Finally, the return value of the useEffect() hook is commonly used to clean up subscriptions and cancel repetitive functions like setInterval(). In our example, we do exactly that and call clearInterval() on executing our sampleInterval() callback function.

Irakli Tchigladze avatar Irakli Tchigladze avatar

Irakli is a writer who loves computers and helping people solve their technical problems. He lives in Georgia and enjoys spending time with animals.

LinkedIn