Intro
Here we are to talk how to create a countdown timer in react using native hooks.
This timer that we will build is a countdown of 5 minutes, but nothing will hold you, if you want to try do a stopwatch based on this material.
Using the useEffect()
and useState()
hooks is possible to store the data of your time and update on screen in real time, but to do that we will need the help from the function setTimeout()
.
Let's begin!
To start our project make shure that your project is a React project in Typescript or javascript, you can create those with create-react-app, next or vite.
If is your first try that is how you create the project:
npx create-react-app my-app --template typescript
# or
yarn create react-app my-app --template typescript
How this works?
This timer we are about to create needs a start time, in this project we will set to 5 minutes.
Now we need to think how tom make this work, the amount time could be in hours, minutes or seconds, we will use seconds just by the fact that is easier to convert seconds to minutes or hours, because all seconds will be a integer number.
Starting the code
So the first thing that we will do is to import our hooks and stablish our start time:
import { useEffect, useState } from "react";
const COUNTDOWN_AMOUNT_TOTAL = 5 * 60; // 5 minutes for timer
In this way our variable start in 5 minutes, cause every minute has 60 seconds, with clean code rules we use this equation to have the value amount in seconds.
Timer
To start this timer we need a react function, that we'll name Timer()
, we need this function because every hook must be inside a react function to work.
So our code is like that:
import { useEffect, useState } from "react";
const COUNTDOWN_AMOUNT_TOTAL = 5 * 60; // 5 minutes for timer
export function Timer(){
const [seconds, setSeconds] = useState<number>(COUNTDOWN_AMOUNT_TOTAL);
}
Here we create our function and create our state variable for the seconds amount, and started them with our start value, the start value variable is create outside our function just to when the code runs that value will be mount just one time and not be recreated every time that the useEffect()
changes.
How we need to update the state every second we'll use the useEffect()
:
import { useEffect, useState } from "react";
const COUNTDOWN_AMOUNT_TOTAL = 5 * 60; // 5 minutes for timer
export function Timer(){
const [seconds, setSeconds] = useState<number>(COUNTDOWN_AMOUNT_TOTAL);
useEffect(()=>{
if(seconds > 0){
// +1 second
} else {
// stop
}
}, [seconds])
}
Inside our useEffect()
we have a condition that should make our time pass while our seconds amount is more than 0, and when this amount turns into 0 it should stop the count.
Just to make the code optimized we'll include another variable outside the main function called timeout:
import { useEffect, useState } from "react";
let timeout: NodeJS.Timeout;
const COUNTDOWN_AMOUNT_TOTAL = 5 * 60; // 5 minutes for timer
export function Timer(){
const [seconds, setSeconds] = useState<number>(COUNTDOWN_AMOUNT_TOTAL);
useEffect(()=>{
if(seconds > 0){
timeout = setTimeout(() => {
setSeconds((state) => state - 1);
}, 1000);
} else {
clearTimeout(timeout);
}
}, [seconds])
}
Now our timer is already working, counting precisaly every second, because in the function setTimeout()
we set a arrow function that changes the state of seconds every 1000 miliseconds (1 second), this will happen every time that seconds is changed, because we passed seconds as params for the useEffect(() => {}, [seconds])
, when it comes to 0 with the clearTimeout()
the timer will stop.
Just because i'm usign typescript i needed to declare the types of every varibale.
Refining
After create the timer we see that it is only a countdown in seconds, and it is never shown in screen, how can we show this in screen and separate minutes from seconds?
If every minute has 60 seconds we just need of 2 equations:
import { useEffect, useState } from "react";
let timeout: NodeJS.Timeout;
const COUNTDOWN_AMOUNT_TOTAL = 5 * 60; // 5 minutes for timer
export function Timer(){
const [seconds, setSeconds] = useState<number>(COUNTDOWN_AMOUNT_TOTAL);
const displaySeconds = seconds % 60;
const displayMinutes = Math.floor(seconds / 60);
useEffect(()=>{
if(seconds > 0){
timeout = setTimeout(() => {
setSeconds((state) => state - 1);
}, 1000);
} else {
clearTimeout(timeout);
}
}, [seconds])
}
To show the minutes we need to divide the seconds by 60 and because this division can be a uneven number we need to use the function Math.floor()
that returns only the number before the comma.
To show the seconds we need the rest of this dvision, and to take the rest we need the operator %, the rest of this division is the seconds in that specific minute.
Now is possible to take this varibles and put in the screen:
import { useEffect, useState } from "react";
let timeout: NodeJS.Timeout;
const COUNTDOWN_AMOUNT_TOTAL = 5 * 60; // 5 minutes for timer
export function Timer(){
const [seconds, setSeconds] = useState<number>(COUNTDOWN_AMOUNT_TOTAL);
const displaySeconds = seconds % 60;
const displayMinutes = Math.floor(seconds / 60);
useEffect(()=>{
if(seconds > 0){
timeout = setTimeout(() => {
setSeconds((state) => state - 1);
}, 1000);
} else {
clearTimeout(timeout);
}
}, [seconds]);
return(
<>
<h1>{displayMinutes}</h1>
<p>:</p>
<h1>{displaySeconds}</h1>
</>
)
}
Conclusion
- We learn the concept to create a timer;
- We saw how we can use
useState()
anduseEffect()
hooks to update the data. - Learned about
setTimeout()
to pass the time with accuracy. - And finally we build a countdown timer.
Hope this have helped you and do not be limited by only what's written in here, be creative and use this to expand your knowledge.
Top comments (0)