Countdown Timer with React Hooks

joshtronic

React has simplified and reduced the amount of effort that goes into front end development. The addition of React Hooks has reduced the complexity even further by eliminating the need for classes when you are in need of state management. Building a countdown timer is a great way to leverage the power of React’s automatic updating of elements and can use make use of hooks to track the amount of time left on the timer.

Also, with some major holidays as well as the New Year approaching, ‘tis the season for building a countdown timer!

Getting Started

We’re going to be using React in one it’s purest forms, without any additional dependencies. Since we will be using React Hooks, you will need to be running a version of React that supports it.

React Hooks became stable in v16.8 of React, so if you’ve recently started a project, you are probably in the clear.

Not using React? You can accomplish everything in this article with pure JavaScript! Check out Building a Countdown Timer in JavaScript

Recommended React and GraphQL course

Calculating How Much Time is Left

The heavy lifting in a countdown timer is done by the logic that calculates the time remaining between the timer’s end time and the current time.

We’re going to be counting down to the New Year, and because we will need to call this particular code when the page loads, and every second to get the latest time remaining, we’re going to wrap the logic into it’s own method:

const calculateTimeLeft = () => {
  const difference = +new Date("2020-01-01") - +new Date();
  let timeLeft = {};

  if (difference > 0) {
    timeLeft = {
      days: Math.floor(difference / (1000 * 60 * 60 * 24)),
      hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
      minutes: Math.floor((difference / 1000 / 60) % 60),
      seconds: Math.floor((difference / 1000) % 60)
    };
  }

  return timeLeft;
};

This method calculates the difference between the two dates (after casting them to Unix timestamps in milliseconds) and if there’s any time remaining, does some magic to calculate the number of days, hours, minutes and seconds remaining. It then returns the value so we can use it elsewhere in our project.

Hooking up the State and Effect

React Hooks allow you to add in state management capabilities to existing functional components without having to convert them to a class. If you’re not “hooked” yet, then you’re missing out, because it’s pretty magical, especially when you’re working with more complex functional components that you’d prefer to not convert.

All that said, to make our countdown timer work, we will need to wire up the time remaining method we previously coded to update the state:

const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());

useEffect(() => {
  setTimeout(() => {
    setTimeLeft(calculateTimeLeft());
  }, 1000);
});

The first line pulls out timeLeft which will carry our time left object of intervals and provide us with a method to set the state. On component load, the timeLeft value is set to the current time left value.

The useEffect line is what updates the amount of time remaining. Every time that timeLeft is updated in the state, the useEffect fires. Every time that fires, we set a timer for 1 second (or 1,000ms) which after that time has elapsed, will update the time left.

The cycle will continue every second thereafter.

Displaying the Time Left

Now that we have a working hook that holds the time left as an object, and is being updated every second, now we can build out our display components.

To do so, we’re going to loop through the properties of the timeLeft object and add an element to our components array. Only if the timer interval has a value above zero, that is:

const timerComponents = [];

Object.keys(timeLeft).forEach(interval => {
  if (!timeLeft[interval]) {
    return;
  }

  timerComponents.push(
    <span>
      {timeLeft[interval]} {interval}{" "}
    </span>
  );
});

The extra {" "} is so the text doesn’t run into each other.

To use our timerComponents array, all we need to do is check it’s length, and either return it, or let the user know that the timer had already elapsed:

return (
  <div>
    {timerComponents.length ? timerComponents : <span>Time's up!</span>}
  </div>
);

Putting it All Together

The only thing left to do now is to wrap everything we’ve done thus far into a functional React component:

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

function CountdownTimer() {
  const calculateTimeLeft = () => {
    const difference = +new Date("2020-01-01") - +new Date();
    let timeLeft = {};

    if (difference > 0) {
      timeLeft = {
        days: Math.floor(difference / (1000 * 60 * 60 * 24)),
        hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
        minutes: Math.floor((difference / 1000 / 60) % 60),
        seconds: Math.floor((difference / 1000) % 60)
      };
    }

    return timeLeft;
  };

  const [timeLeft, setTimeLeft] = useState(calculateTimeLeft());

  useEffect(() => {
    setTimeout(() => {
      setTimeLeft(calculateTimeLeft());
    }, 1000);
  });

  const timerComponents = [];

  Object.keys(timeLeft).forEach(interval => {
    if (!timeLeft[interval]) {
      return;
    }

    timerComponents.push(
      <span>
        {timeLeft[interval]} {interval}{" "}
      </span>
    );
  });

  return (
    <div>
      <h1>Alligator.io New Year's 2020 Countdown</h1>
      <h2>With React Hooks!</h2>
      {timerComponents.length ? timerComponents : <span>Time's up!</span>}
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<CountdownTimer />, rootElement);

And if you want to see this code live and in action, you can check out the code over on Code Sandbox

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#