top of page

How to Create Timer UI in React using setInterval, useEffect and useState



Create a simple timer with a slider animation using React. The timer will count down from 1 minute and the slider will move across a fixed width container to show the progress of the timer. We will use setInterval to keep updating time after every interval of time, and using useState hooks to update time and slider position, and lets call all of this in an useEffect, and we will use CSS to style the slider animation.



Setting initial Time and Slider position

We initialise our state variable to our desired values here in case 60sec for timer, and 0 as initial slider position.

const [seconds, setSeconds] = useState(60);
const [sliderPosition, setSliderPosition] = useState(0);


How the Timer is Updated Using useEffect, setInterval

useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((prevSeconds) => {
        if (prevSeconds === 0) {
          return 60;
        } else {
          return prevSeconds - 1;
        }
      });
      setSliderPosition((position) => position + 100 / 60);
    }, 1000);
    return () => clearInterval(interval);
}, []);

The useEffect hook is used to set an interval that updates the timer and slider position every second. The interval is created using the setInterval function, which takes a callback function and a time interval in milliseconds. The callback function inside the setInterval function updates the seconds state variable using the setSeconds function. It uses a callback to access the previous value of seconds, and checks if it is equal to 0. If it is, it returns 60 to reset the timer to its initial value. Otherwise, it decrements the value of seconds by 1. The callback function also updates the sliderPosition state variable using the setSliderPosition function. It uses a callback to access the previous value of sliderPosition, and adds 100/60 (which is the width of the slider divided by the total time in seconds) to it. This causes the slider to move across the width of its container as the timer counts down.

Finally, the useEffect hook returns a cleanup function that clears the interval using the clearInterval function. This ensures that the interval is stopped when the component is unmounted or updated. By passing an empty array as the second argument to the useEffect hook, this code ensures that the effect runs only once, when the component is mounted. This is because there are no dependencies in the array, so there is nothing to trigger the effect to run again.


Slider
<div className="slider"
   style={{ transform: `translateX(${sliderPosition}%)` }}
>
   <span className="slide"></span>
</div>


.slider {
  height: 100%;
  width: 100%;
  position: absolute;
  left: 0;
  transition: transform 0.5s;
}

.slide{
  width: 40px;
  height: 20px;
  background-color: yellow;
  position: absolute;
  border-radius: 9999px;
  top: -4px;
}


The slider is a visual component that shows the progress of the timer by moving across a fixed-width container. The slider is implemented as a div element with the class name "slider", and it contains a span element with the class name "slide". The span element is used to display a small visual indicator of the slider's position.


The slider's position is controlled by the sliderPosition state variable, which is updated every second by the setSliderPosition function inside the useEffect hook. The sliderPosition variable is a number that represents the percentage of the slider's width that the slider should be moved to the right.


The slider's position is set using the style prop on the div element. A style prop is an object that contains CSS properties as keys and their values as values. In this case, the transform property is used to translate the slider horizontally by a percentage amount equal to the current value of sliderPosition. The translateX() function is a CSS function that moves an element horizontally by a given amount, in this case, the percentage value of sliderPosition.



Complete code

import { useEffect, useState } from "react";
import "./styles.css";

export default function Timer() {
  const [seconds, setSeconds] = useState(60);
  const [sliderPosition, setSliderPosition] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setSeconds((prevSeconds) => {
        if (prevSeconds === 0) {
          return 60;
        } else {
          return prevSeconds - 1;
        }
      });
      setSliderPosition((position) => position + 100 / 60);
    }, 1000);
    return () => clearInterval(interval);
  }, []);

  return (
    <div className="timer-container">
      <div className="time-remaining">Time remaining: {seconds} seconds</div>
      <div className="slider-container">
        <div
          className="slider"
          style={{ transform: `translateX(${sliderPosition}%)` }}
        >
          <span className="slide"></span>
        </div>
      </div>
    </div>
  );
}


CSS code
.timer-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 30px 0;
}

.time-remaining {
  font-size: 24px;
  margin-bottom: 150px;
  color: white;
}

.slider-container {
  width: 100%;
  height: 10px;
  border: 1px solid #ccc;
  border-radius: 5px;
  position: relative;
}

.slider {
  height: 100%;
  width: 100%;
  position: absolute;
  left: 0;
  transition: transform 0.5s;
}

.slide{
  width: 40px;
  height: 20px;
  background-color: yellow;
  position: absolute;
  border-radius: 9999px;
  top: -4px;
}



bottom of page