MediumStopwatch with React. Hey, today we are gonna create a… | by Paani | Medium
Sitemap

Stopwatch with React

Hey, today we are gonna create a stopwatch using react. It will be a simple front-end application. We are gonna walk through all the steps together.

14 min readDec 12, 2022

--

First of all, we’ll create a React app, and I’m using Visual Studio Code for this project. You can choose this or any code editor of your choice.

Create a React app:

To do that, go inside the folder you want to save this project. And open a terminal there, and in the terminal, type this command

npx create-react-app stopwatch

Press enter or click to view image in full size

Here, npx is a command that is basically the package runner, and create-react-app will create the frontend part of a webapp. If you wish to extend it further, you can connect it to the backend in the future. Stopwatch is the name of the app we are creating.

You will see a folder named “Stopwatch” created, which has the following folders and files inside it. And if you extend the public and src folders, you will notice these files inside them.

The node_modules folder contains all the dependencies. There are two files: package.json and package-lock.json, which contain information about the project’s dependencies. There’s also a README file in which you can store information about your project to give others an overview of it. Inside the public folder, there’s an index.html page, which is the first page that’s going to be rendered. And the manifest.json file describes our application (name, author, etc. ) and it’s used by devices to get easy access to this app if placed on the homescreen. robots.txt prevents search engine crawlers and bots from crawling up our site. Now, delete all the files present in the src folder except index.js. Also delete files inside the public folder except index.html, manifest.json, and robot.txt, and go inside the manifest.json file and delete all the keys related to icons.

Inside the index.js file

Inside the index.js file, delete everything so that we can create everything from scratch. Firstly, we need to import react and react-dom. To do this, we’ll use these commands:

import React from 'react'
import ReactDOM from 'react-dom'

Now, to render the contents of the app, we’ll use the ReactDOM.render() command, which takes up 2 parameters. The first parameter tells what to render, and the second describes where to render. If you open the index.html file, you will see a div with an id of "root" inside the body tag.

So, we will render our components inside this div whose id is "root."

The next question is: what component to render?

We’ll render the App component, which we’ll create later, but first we’ll see the command to do this.

ReactDOM.render(<App />, document.getElementById("root"))

So, our index.js file will look like this after all this:

Press enter or click to view image in full size
index.js

Create App component

Inside our src folder, create another folder named “components” that will store the components, and inside this components folder, create 2 files named “App” with extensions “.js” and “.css” (such that those files are App.js and App.css). You can also put these files in their own folder. It is entirely up to you and how you want to organise your folders and files. Since we’ll have fewer components, we won’t be creating a separate folder for each component.

Inside the App.js file

Import React from “react” and also the App.css file using import ‘./App.css’.App component will store the stopwatch component inside it, and we’ll make this a functional component. If you want to know more about it, you can read about it here. So we’ll create a function named "App" called "function App(){}"and inside its body we’ll return a div with the class name "container" which will have the stopwatch component inside it. To access the App component, i.e., this file inside the index.js file, we’ll have to export this file, and that can be done with "export default function_name" which is "App," or this can be done within one line too, by placing export default prior to function.

export default App

Inside the App.js file

Import React from “react” and also the App.css file using import "./App.css". App component will store the stopwatch component inside it, and we’ll make this a functional component. If you want to know more about it, you can read about it here. So we’ll create a function named "App" which is "function App(){}" and inside its body we’ll return the stopwatch component inside a div with the class name "container". To access the App component, i.e., this file inside the index.js file, we’ll have to export this file, and that can be done with "export default function_name" which is App. This can also be done in a single line by placing export default before function.

export default App

Press enter or click to view image in full size
App.js

Also, to get access to this component in index.js, we’ll have to import this file inside index.js. So add import App from './components/App' after imports from react. Here “./components/App” is the relative location of App from index.

Create Stopwatch component

Inside component folder, again create two files named Stopwatch.js and Stopwatch.css, import React and stopwatch.css file inside stopwatch.js file and create a function named Stopwatch and export it. After all these import this stopwatch file as “Stopwatch” inside App component as we did earlier while creating App component.

In Stopwatch function, we’ll return a div with class name “stopwatch” (we have added the class name so that we can style it but we’ll do it later) Inside stopwatch div, we’ll create a timer div and a buttons div and we will have 3 buttons, Start/Stop, Reset and Pause. Their functionality is as their name suggests.

Let’s add these buttons using button tag of html and place these inside their own div with class name “buttons” which is inside stopwatch div.

function Stopwatch(){
return (
<div className="stopwatch">
<div className="timer">
</div>
<div className="buttons">
<button>Start</button>
<button>Pause</button>
<button>Reset</button>
</div>
</div>
)
}

Now, the functionality of a stopwatch, Initially, timer should be set to 00.00.00, when you will click the start button timer should start and it should increment the timer value as the time passes by and it should change its name to stop and when we’ll click the pause button, it should pause the timer and change its name to resume and when we will click the stop button it should stop the timer and again change back its name to start and reset button should reset the timer to 00.00.00.

Okay, so some points to note:

  • Our app does not do anything after rendering until the start button is clicked, and we need to update our UI every second.
  • The pause button will pause the UI update, and as the resume button is pressed, it should start the update process from where it was paused.
  • Restart has to save everything as it was at the beginning before clicking the start button.

So, considering all these points, we need something that will keep the value of time between every render and, at the same time, needs to get updated every second on the UI.

So, we will use the state hook to keep a value between the renders and to trigger the rendering after it is updated, which can be done by:

const [seconds, setSeconds] = React.useState(0)

we can also do something like const [seconds, setSeconds] = useState(0)

But, for that we need to import it so we can just add this line before the Stopwatch function import {useState} from React and everything will work fine. This line is importing State hook from the react module so that we can use it directly in our code(This is called object destructuring).

The state hook only does two things:

  • It keeps a value between the renders so that it doesn’t get lost.
  • It gives you a function to update this value and trigger a re-render.

Here, seconds is keeping the value, setSeconds is the function that will update the second value and trigger re-rendering, and 0 is the initial value of seconds that we gave it. So, add this line before the return statement inside the Stopwatch function.

Get Paani’s stories in your inbox

Join Medium for free to get updates from this writer.

And we know we need to update the second value after the start button is clicked, so to do this, we will add one more state that will make the seconds state increment every second. This will be a boolean value with the name “isActive” and it will tell our app if the timer is running or not. If it is false, then the timer won’t be running, but if it’s true, that means the timer is running. and by default it will be false.

const [isActive, setIsActive] = React.useState(false)

Start functionality:

Now, the start button has to start the timer, so to do that, we need to set isActive to true when the start button is clicked. To achieve this, we’ll create a function called “handleClick” (you can name it whatever you want) and update the value of “isActive” from false to true.

function handleClick(){
setIsActive(prevState => !prevState)
if(!isActive)
setSeconds(0)
}

You know start button is also our stop button, so the above code will make sure the start button will change isActive’s value from false to true and from true to false. As we’ll click the start button again, the timer should start at 0.0.0. IsActive is true when the timer is running, so as we stop the timer, isActive becomes false, and we set the seconds state to 0.

setIsActive is taking another function as a parameter (a callback function), which takes isActive’s value and negates it (in other words, if the value of isActive is true, it will change it to false, and vice versa).

To make the start button have this function and do this after being clicked, let’s add an attribute onClick and assign its value to {handleClick} . OnClick is an event that occurs when the item for which it is defined as an attribute is clicked, and it executes the function assigned as its value. And we also need to make sure its value is changed after being clicked. This is also possible with the “is Active” state. So, when isActive is false, indicating that the timer is not running, the button should say “start,” and when it is true, indicating that the timer is running, the button should say “stop”. We have the logic; all that remains is to code it. We’ll be doing this by using the ternary operator (?:).

<button onClick={handleClick}>{ isActive ? "Stop" : "Start" }</button>

Here, we have added curly braces({}) between the button tags as it allows javascript code to be added between the JSX (JSX allows us to write HTML in React). Code between {} says if isActive is true, button should show Stop ; if it is false, it should show Start.

Hmm, now the biggest question is: how will we update our timer every second? And how will we ensure that our seconds state is incremented every second?

For that, we’ll use setInterval with one more hook called useEffect. setInterval allows us to run some code at specified intervals of time. useEffect is used to handle side effects, if there are any. In a nutshell, the hook useEffect takes a function and an array as parameters and runs the function whenever the value of any element in the array changes. Let’s look at the code first:

React.useEffect(() => {
let interval
if(isActive){
interval = setInterval(() => {
setSeconds(prev => prev + 1)
}, 1000)
}

return clearInterval(interval)
}, [isActive])

When we’ll click the start button, the isActive state will be true, and we would want the timer to start running, so we’ll define and initialise a variable interval to the setInterval function. setInterval also takes up two parameters: first, a function (a callback function) to run at regular intervals, and second, the interval duration in milliseconds (ms). So, after 1000 ms (1 sec = 1000 ms), we want to increment the seconds value. For that, we will use the setSeconds function in this callback function that we declared to update the value of the seconds state. We will increment seconds by taking the previous value of seconds and adding +1 to it.

Now, the second parameter of useEffect is an empty array for now. Think: when do we have to start and stop the timer? when the start/stop button is clicked. isActive is false in the beginning, but when the start button is clicked, isActive becomes true, and when the stop button is clicked, isActive becomes false again. So, incrementing can depend on the isActive value. So, the array will have “isActive” as its element because, whenever its value changes, our function will start executing or execution will stop. Now, how do we put a stop to this increase?by using clearInterval. So, to stop an interval, we use clearinterval. To do this, we’ll return clearInterval with interval as a parameter.

Reset functionality:

And let’s talk about reset functionality too. The reset button sets our timer to 00.00.00, which means our seconds state is set to 0. Can you think of a way to reset the seconds state to 0 as we press the reset button?If you did, well, great! If you couldn’t, don’t worry; we will go through it together.

Okay, first thing: change is happening to the seconds state after the reset button is clicked, which means we need the onClick event and we are changing the value of a state, so we’ll use the setSeconds function to update the value of this state. so we’ll assign onClick with {handleResetClick} and create a function with the name “handleResetClick()” before the return statement. Inside its body, we’ll pass 0 as a parameter to “setSeconds”. After we press the reset button, the seconds state will be reset to 0. Also, we are setting the isActive state to false, so if the timer is in a running state and the reset button is clicked, we’ll stop the timer and set it to 0.

function handleResetClick(){
setSeconds(0)
setIsActive(false)
}

//reset button changes
<button onClick = {handleResetClick} >Reset</button>

It’s time for the timer. Inside the “stopwatch” div, we’ll create another div with the class name “timer.” Inside this div, add an h1 tag with the value {seconds} between it. It will represent the second value of the timer, and for minutes and hours, we’ll do what we used to do in math class: divide seconds by 60 for minutes and seconds by 3600 for hours. There’s one more thing we need to take care of, i.e., we know we have our seconds and minutes values up to 60 only. So to achieve this, we’ll use the modulo operator (%).

<h1>{Maths.trunc((seconds/ 3600) % 24)} : {Maths.trunc((seconds/60) % 60)} : {Maths.trunc(seconds % 60)}</h1>
// hours minutes seconds

As seconds will increment and will cross 60 or any multiple of 60, seconds%60 will start from 0 again (because modulo gives the reminder of seconds/60) and Math.trunc is for getting only the integer values.

Pause functionality:

Its functionality is the same as the stop button’s, except that it does not set the seconds state value to 0. So, if you are thinking we can just switch the “isActive” state value without making any changes to the “seconds” state, then there’s a problem with that, i.e., the pause button should not start the timer; this button should only work after the timer is in active mode, i.e., running. and when we click the pause button when the timer is not running, it will set the isActive state to true, which in turn will start the timer. This shouldn’t happen, right? What if there is a state that will enable the timer to start and stop only if isActive is true (that’s our pause feature), i.e., only after the start button is clicked? Let’s create a state called isPaused with an initial value of false.

const [ isPaused, setIsPaused ] = React.useState(false)

It should be able to make the timer start and stop, so that means it also affects setInterval, so it should also be an element of useEffect’s second parameter, an array (called a dependency array).

So, here’s an updated version of the useEffect hook.

 React.useEffect(() => {
let interval
if(isActive && !isPaused){
interval = setInterval(() => {
setSeconds(prev => prev + 1)
}, 1000)
}

return () => clearInterval(interval)

},[isActive, isPaused])

Here, we’ll only allow the seconds state to increment if it is in an active state and not being paused.

Add an onClick attribute with the value “handlePause” to the pause button tag, and write a function called handlePause() that, when the pause button is clicked, sets “isPaused” to true and changes its name to “Resume,” and when clicked again, sets isPaused to false. There’s also an if condition that checks to see if the timer is running. If this is the case, only it will be possible to change the state of isPaused. We’ll also see if isPaused is true; if it is, the button will say “Resume,” if it is false, it will say “Pause.”

function handlePause(){
if(isActive){
setIsPause(prevState => !prevState)
}
}

// Pause/Resume button

<button>{isPaused ? "Resume" : "Pause"}</button>

Or we can make this whole pause/resume button visible only when the timer is running by using the isActive state. It says if the timer is running, show the pause button; otherwise, don’t show anything.

{ isActive ? <button onClick={handlePause}>{isPaused ? "Resume" : "Pause"}</button> : ""}

Here’s the stopwatch.js file code:

Press enter or click to view image in full size
Stopwatch.js -1
Press enter or click to view image in full size
Stopwatch.js-2

We are done with our functionalities, so to see if all the functionalities are working fine, first see if you are in the correct directory, i.e., inside your project folder (for me, it’s the stopwatch folder). If not, get into that using cd “location of your project/project_folder_name” (I was in the projects directory where my stopwatch folder was, so I did cd stopwatch).Then, open the command prompt and type npm start in the command line.

npm start will start the app on port 3000. It is port 3000 for me; if your port is already in use, it may be on a different port for you. And the app will look something like this when it’s running on Chrome.

Press enter or click to view image in full size

It looks kind of dull, so we’ll now style it. So, here are the styles I have added inside the App.css file (.container says there’s a class named container inside the App.js file.)

Press enter or click to view image in full size
App.css file

and styles I have added in Stopwatch.css:

Press enter or click to view image in full size
Stopwatch.css

After adding style, our webapp looks like this. It looks a lot better than webapp with no style.

Press enter or click to view image in full size
Stopwatch app

With this, it’s a wrap, guys! If you reached this point, thank you so much for reading this article, and if it helped you in any way, do let me know. If there are any suggestions or improvements, that’s also highly appreciated and welcomed.

Refer these for reference:

--

--

Paani
Paani

Written by Paani

This is my safe space. I write what I learn(ML, Web Dev), some stories and my perspective towards anything which I would wanna share to world.