Open In App

Lap Memory Stopwatch using React

Last Updated : 21 Sep, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Stopwatch is an application which helps to track time in hours, minutes, seconds, and milliseconds. This application implements all the basic operations of a stopwatch such as start, pause and reset button. It has an additional feature using which we can keep a record of laps which is useful when we have to note time for certain checkpoints.

Preview of Final Output:

gfg

Prerequisites and Technologies:

 

Approach:

This program creates a functional stopwatch timer with start, pause, reset, and lap features. It maintains state variables for hours, minutes, seconds, and milliseconds, ensuring real-time updates using the “useEffect” hook. Proper interval clearing prevents memory leaks, delivering a straightforward and reliable stopwatch for time tracking.

 

Functionalities:

  • When users click “Start,” the timer begins, disabling the button with a “not-allowed” cursor.
  • “Pause” stops the timer, and “Reset” sets all time units to zero.
  • The program also offers a “Lap” feature for recording lap times, allowing users to track multiple intervals

 

Steps to create the application :

Step 1: Set up React project using the command

npx create-react-app <<name of project>>

Step 2: Navigate to the project folder using

cd <<Name_of_project>>

Step 3: Create a folder “components” and add three new files in it namely StopWatch.js, Lap.js and StopWatch.css.

Project Structure:

Screenshot-2023-09-19-101917

Project Structure

The updated dependencies in package.json will look like:

"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Example: Write the following code in respective files

  • App.js: This file imports the StopWatch components and exports it.
  • StopWatch.js: This file contains the logic to track time in hours, minutes, seconds, and milliseconds, offering user-friendly controls for starting, pausing, and resetting the timer.
  • Lap.js : This file contains the logic for displaying the laps in a list. From StopWatch.js file we send a prop laps to this file.
  • StopWatch.css: This file contains the design of the StopWatch.js elements.

Javascript




// App.js
  
import './App.css';
import StopWatch from './components/StopWatch';
  
function App() {
  return (
    <div className="App">
      <StopWatch />
    </div>
  );
}
  
export default App;


Javascript




// StopWatch.js
import React, { useState, useEffect } from "react";
import "./StopWatch.css";
import Lap from "./Lap";
  
export default function StopWatch() {
    const [seconds, setSeconds] = useState(0);
    const [minutes, setMinutes] = useState(0);
    const [hours, setHours] = useState(0);
    const [miliSeconds, setMiliSeconds] = useState(0);
    const [laps, setLaps] = useState([]);
    const [isRunning, setIsRunning] = useState(false);
  
    const formatWithLeadingZero = (number) => {
        if (number < 10) return "0" + number;
        else return number.toString();
    };
  
    useEffect(() => {
        let interval;
  
        if (isRunning) {
            interval = setInterval(() => {
                setMiliSeconds((miliSeconds) => {
                    if (miliSeconds >= 99) {
                        setSeconds((seconds) => {
                            if (seconds >= 59) {
                                setMinutes((minutes) => {
                                    if (minutes >= 59) {
                                        setHours((prevHours) => prevHours + 1);
                                        return 0;
                                    } else {
                                        return minutes + 1;
                                    }
                                });
                                return 0;
                            } else {
                                return seconds + 1;
                            }
                        });
                        return 0;
                    } else {
                        return miliSeconds + 1;
                    }
                });
            }, 10);
        }
        return () => clearInterval(interval);
    }, [isRunning]);
  
    const handleStart = () => {
        setIsRunning(true);
    };
  
    const handlePause = () => {
        setIsRunning(false);
    };
  
    const handleLap = () => {
        const lapTime =
            formatWithLeadingZero(hours) +
            ":" +
            formatWithLeadingZero(minutes) +
            ":" +
            formatWithLeadingZero(seconds) +
            "." +
            formatWithLeadingZero(miliSeconds);
        setLaps((prevLaps) => [...prevLaps, lapTime]);
    };
  
    const handleReset = () => {
        setIsRunning(false);
        setMiliSeconds(0);
        setSeconds(0);
        setMinutes(0);
        setHours(0);
        setLaps([]);
    };
  
    return (
        <div className="container">
            <div className="timeDisplay">
                {formatWithLeadingZero(hours)} : {formatWithLeadingZero(minutes)} :{" "}
                {formatWithLeadingZero(seconds)} : {formatWithLeadingZero(miliSeconds)}
            </div>
            <div className="buttons">
                <button
                    className="btn"
                    onClick={handleStart}
                    disabled={isRunning}
                    style={{ cursor: isRunning ? "not-allowed" : "pointer" }}
                >
                    Start
                </button>
                <button className="btn" onClick={handlePause}>
                    Pause
                </button>
                <button className="btn" onClick={handleLap}>
                    Lap
                </button>
                <button className="btn" onClick={handleReset}>
                    Reset
                </button>
            </div>
            <Lap laps={laps} />
        </div>
    );
}


Javascript




// Lap.js
import React from "react";
  
export default function Laps({ laps }) {
    const calculateTimeDifference = (timeString1, timeString2) => {
        const time1 = new Date(`1970-01-01T${timeString1}Z`);
        const time2 = new Date(`1970-01-01T${timeString2}Z`);
        const timeDiff = Math.abs(time2 - time1);
        const hours = Math.floor(timeDiff / 3600000).toString().padStart(2, '0');
        const minutes = Math.floor((timeDiff % 3600000) / 60000).toString().padStart(2, '0');
        const seconds = Math.floor((timeDiff % 60000) / 1000).toString().padStart(2, '0');
        const milliseconds = ((timeDiff % 1000) / 10).toString().padStart(2, '0');
        const resultString = `${hours}:${minutes}:${seconds}.${milliseconds}`;
        return resultString;
    }
  
    return (
        <div className="laps" style={{ display: (laps.length) ? 'block' : 'none' }}>
            <h3><span>Lap</span><span>Time</span><span>Total Time</span></h3>
            <ul>
                {laps.map((lap, index) => (
                    <li key={index}>
                        <span>{`Lap ${index + 1}`}</span>
                        <span>{calculateTimeDifference(lap, (index !== 0) ? laps[index - 1] : "00:00:00.00")}</span>
                        <span>{lap}</span>
                    </li>
                ))}
            </ul>
        </div>
    );
};


CSS




/* StopWatch.css */
  
body {
    margin: 0;
    padding: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    background-color: #f0f0f0;
    font-family: Arial, sans-serif;
}
  
.container {
    padding: 30px;
    border: 1px solid #ced4da;
    border-radius: 10px;
    background: #fff;
    box-shadow: 0 0 6px rgba(0, 0, 0, 0.25);
    margin: 5px;
    width: 100%;
    max-width: 400px;
    box-sizing: border-box;
}
  
.timeDisplay {
    padding: 20px;
    font-size: 30px;
    box-shadow: 0 0 6px rgba(0, 0, 0, 0.25);
    border-radius: 0.25em;
    text-align: center;
}
  
.buttons {
    display: flex;
    justify-content: center;
    margin-top: 20px;
}
  
button.btn {
    padding: 10px 20px;
    outline: none;
    border: 1px solid #ced4da;
    margin: 5px;
    border-radius: 4px;
    cursor: pointer;
    background: #1d9bf0;
    color: #fff;
    font-size: 16px;
    transition: all 0.5s;
}
  
button.btn:hover {
    background-color: #1879ba;
}
  
.laps {
    margin-top: 20px;
}
  
.laps h3 {
    text-align: left;
    display: flex;
    justify-content: space-between;
    margin: 5px;
}
  
.laps ul {
    list-style-type: none;
    padding: 0;
}
  
.laps li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: 0px 5px 10px 5px;
}
  
@media screen and (max-width: 420px) {
    .buttons {
        display: grid;
        grid-template-columns: 1fr 1fr;
    }
}


Steps to run the application:

Step 1: Type the following command in terminal.

npm start

Step 2: Open web-browser and type the following URL

http://localhost:3000/

Output:

Recording-2023-09-19-000954

Created StopWatch using ReactJSR



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads