≡ Menu

Building a High-Precision Stopwatch in React: A Step-by-Step Guide

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 % 60 ensures that when we hit 61 seconds, the display shows 01 instead of 61.

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

  • useRef is essential for storing the setInterval ID without causing extra re-renders.

  • Math.floor keeps 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

 

 

{ 0 comments… add one }

Leave a Comment