Open In App

Creating a Timer Component with useEffect Hook in React

Timer Component using React along with its useEffect hook will not only display the elapsed time since the component mounts but also allow users to set and manage the countdown timer dynamically. We will harness the power of the useEffect hook to manage side effects and update the timer seamlessly.

Output Preview: Let us have a look at how the final feature will look like.



Output Preview

Prerequisites:

Functionalities of Timer Component:

Approach to create Timer Component:

Steps to Create the Project:

Step 1: Create a new React project using Create React App.

npx create-react-app timer-app

Step 2: Change the directory:



cd timer-app

Project Structure:

Project Structure

The updated dependencies in package.json file 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: Below is the code example of the Timer Component with useEffect.




// App.js
 
import React from 'react';
import './App.css';
import Timer from './Timer';
 
function App() {
    return (
        <div className="App">
            <header className="App-header">
                <h1>
                    Timer App
                </h1>
                <Timer />
            </header>
        </div>
    );
}
 
export default App;




// Timer.js
 
import React, {
    useState,
    useEffect
} from "react";
import "./Timer.css";
 
const Timer = () => {
    const [hours, setHours] = useState(0);
    const [minutes, setMinutes] = useState(5);
    const [seconds, setSeconds] = useState(0);
    const [isActive, setIsActive] = useState(false);
    const [isEditing, setIsEditing] = useState(false);
    const [editHours, setEditHours] = useState(0);
    const [editMinutes, setEditMinutes] = useState(0);
    const [editSeconds, setEditSeconds] = useState(0);
 
    useEffect(() => {
        let interval = null;
        if (isActive && (hours > 0 ||
            minutes > 0 || seconds > 0)) {
            interval = setInterval(() => {
                if (seconds === 0) {
                    if (minutes === 0) {
                        if (hours === 0) {
                            clearInterval(interval);
                            setIsActive(false);
                        } else {
                            setHours(hours - 1);
                            setMinutes(59);
                            setSeconds(59);
                        }
                    } else {
                        setMinutes(minutes - 1);
                        setSeconds(59);
                    }
                } else {
                    setSeconds(seconds - 1);
                }
            }, 1000);
        } else {
            clearInterval(interval);
        }
 
        return () => clearInterval(interval);
    }, [isActive, hours, minutes, seconds]);
 
    const toggleTimer = () => {
        setIsActive(!isActive);
        // Exit editing mode when starting the timer
        setIsEditing(false);
    };
 
    const resetTimer = () => {
        if (!isEditing) {
            setHours(editHours);
            setMinutes(editMinutes);
            setSeconds(editSeconds);
            setIsActive(!isActive);
        }
        setIsActive(false);
    };
 
    const handleInputChange = (e) => {
        const { name, value } = e.target;
        if (name === "hours") {
            setEditHours(parseInt(value));
        } else if (name === "minutes") {
            setEditMinutes(parseInt(value));
        } else if (name === "seconds") {
            setEditSeconds(parseInt(value));
        }
    };
 
    const toggleEdit = () => {
        if (isEditing) {
            setHours(editHours);
            setMinutes(editMinutes);
            setSeconds(editSeconds);
        }
        setIsEditing(!isEditing);
    };
 
    return (
        <div className="timer-container">
            {
                isEditing ? (
                    <div className="editing-container">
                        <div className="input-group">
                            <label>HH:</label>
                            <input
                                type="number"
                                name="hours"
                                value={editHours}
                                onChange={handleInputChange}
                                min="0"
                            />
                        </div>
                        <div className="input-group">
                            <label>MM:</label>
                            <input
                                type="number"
                                name="minutes"
                                value={editMinutes}
                                onChange={handleInputChange}
                                min="0"
                                max="59"
                            />
                        </div>
                        <div className="input-group">
                            <label>SS:</label>
                            <input
                                type="number"
                                name="seconds"
                                value={editSeconds}
                                onChange={handleInputChange}
                                min="0"
                                max="59"
                            />
                        </div>
                        <button className="start-btn"
                            onClick={toggleEdit}>
                            Start Timer
                        </button>
                    </div>
                ) : (
                    <div>
                        <div className="timer-display">
                            <span>
                                {
                                    hours.toString()
                                        .padStart(2, "0")
                                }:
                            </span>
                            <span>
                                {
                                    minutes.toString()
                                        .padStart(2, "0")
                                }:
                            </span>
                            <span>
                                {
                                    seconds.toString()
                                        .padStart(2, "0")
                                }
                            </span>
                        </div>
                        <div className="timer-controls">
                            <button onClick={toggleTimer}>
                                {
                                    isActive ?
                                        "Pause" :
                                        "Start"
                                }
                            </button>
                            <button onClick={resetTimer}>
                                Reset
                            </button>
                            <button onClick={toggleEdit}>
                                Edit
                            </button>
                        </div>
                    </div>
                )}
        </div>
    );
};
 
export default Timer;




/* App.css */
 
.App {
    text-align: center;
}
 
.App-header {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: calc(10px + 2vmin);
    color: white;
    background: #03001e;
    /* fallback for old browsers */
    background:
        -webkit-linear-gradient(to right, #fdeff9, #ec38bc, #7303c0, #03001e);
    /* Chrome 10-25, Safari 5.1-6 */
    background:
        linear-gradient(to right, #fdeff9, #ec38bc, #7303c0, #03001e);
    /*
        W3C, IE 10+/ Edge, Firefox 16+,
        Chrome 26+, Opera 12+, Safari 7+
    */
}




/* Timer.css */
 
.timer-container {
    text-align: center;
}
 
.timer-display {
    font-size: 3rem;
    font-weight: bold;
    margin-bottom: 1rem;
}
 
.timer-controls button {
    margin: 0 0.5rem;
    padding: 0.5rem 1rem;
    font-size: 1rem;
    font-weight: 500;
    cursor: pointer;
    background-color: #fff;
    color: #007bff;
    border: none;
    border-radius: 5px;
}
 
.timer-controls button:hover {
    background-color: #0056b3;
    color: #fff;
}
 
.editing-container {
    display: flex;
    flex-direction: column;
    align-items: start;
    justify-content: flex-start;
}
 
.input-group {
    margin-bottom: 1rem;
    display: flex;
    flex-direction: row;
    align-items: start;
    justify-content: flex-start;
    width: 10rem;
}
 
.input-group label {
    margin-right: 0.5rem;
}
 
input[type="number"] {
    padding: 0.5rem;
    font-size: 1rem;
    border: 1px solid #ccc;
    border-radius: 5px;
    width: 100%;
}
 
.start-btn {
    background-color: #fff;
    color: #28a745;
    border: none;
    border-radius: 5px;
    padding: 0.5rem 1rem;
    cursor: pointer;
    width: 100%;
}
 
.start-btn:hover {
    background-color: #218838;
    color: #fff;
}

Step to run the App:

npm start

Output: Open your web browser and go to http://localhost:3000 to view the Timer App.

ReactJS Timer App Output


Article Tags :