
Creating a stopwatch is a rite of passage for React developers.
It’s the perfect project to master Hooks, Side Effects, and JavaScript Math.
In this post, we’ll break down a clean, functional implementation and explain the “why” behind the code.
The Core Logic
At its heart, a stopwatch is just a number (milliseconds) that increases at a set interval.
However, making that look like a “clock” requires some clever state management.
import React, { useState, useEffect, useRef } from 'react';
const Stopwatch = () => {
const [isRunning, setIsRunning] = useState(false);
const [time, setTime] = useState(0);
const timerRef = useRef(null);
// ... (logic below)
1. Managing the “Heartbeat” with useEffect
We use useEffect to start and stop the timer. The most important part here is the Cleanup Function.
Without it, if you delete the component or navigate away, the timer would keep running in the background, causing a “memory leak.”
useEffect(() => {
if (isRunning) {
// Increment time by 10ms every 10ms
timerRef.current = setInterval(() => {
setTime((prevTime) => prevTime + 10);
}, 10);
} else {
clearInterval(timerRef.current);
}
return () => clearInterval(timerRef.current); // The Cleanup
}, [isRunning]);
2. The Math: Converting Milliseconds to Time
The time state is just a big number of milliseconds (e.g., 95000). To display this as 01:35:00, we use a formatting helper.
Key Concept: Modulo (
%) > We use the modulo operator to “reset” the numbers. For example,seconds % 60ensures that when we hit 61 seconds, the display shows01instead of61.
const formatTime = (time) => {
const minutes = Math.floor((time / 60000) % 60);
const seconds = Math.floor((time / 1000) % 60);
const milliseconds = Math.floor((time % 1000) / 10);
return `${minutes.toString().padStart(2, '0')}:${seconds
.toString()
.padStart(2, '0')}:${milliseconds.toString().padStart(2, '0')}`;
};
3. Making it Look Professional with padStart
Ever noticed how digital clocks don’t “jump” when the numbers change?
We achieve this using .padStart(2, '0'). This ensures that if the seconds are 5, it displays as 05. This prevents the UI from “jittering” as the width of the numbers changes.
Summary of Performance
Because this stopwatch updates every 10ms, React is re-rendering the component 100 times per second.
For a simple UI, this is perfectly fine!
However, if you add complex animations or many child components, you might want to wrap the display in its own “leaf” component to keep the app snappy.
Key Takeaways
-
useRefis essential for storing thesetIntervalID without causing extra re-renders. -
Math.floorkeeps our time units as whole integers. -
String Concatenation (via Template Literals) turns raw math into a readable UI.
Useful links below:
Let me & my team build you a money making website/blog for your business https://bit.ly/tnrwebsite_service
Get Bluehost hosting for as little as $1.99/month (save 75%)…https://bit.ly/3C1fZd2
Best email marketing automation solution on the market! http://www.aweber.com/?373860
Build high converting sales funnels with a few simple clicks of your mouse! https://bit.ly/484YV29
Join my Patreon for one-on-one coaching and help with your coding…https://www.patreon.com/c/TyronneRatcliff
Buy me a coffee https://buymeacoffee.com/tyronneratcliff



