Front-end Machine Coding Series #5: Building a Lightweight React Timer


React gives you powerful tools like useState and useEffect to manage state and lifecycles. But sometimes you want to perform side effects or store values without triggering re-renders. That’s where useRef becomes incredibly handy.
In this article, we’ll build a smart counter using only useRef, complete with Start, Pause, and Reset controls, and it won’t cause a single re-render while counting. Guess what, it still one of the most asked interview problems that can give headache to anyone who doesn’t have any idea of using useRef.
Problem Statement
We want to build a performance-efficient counter component in React that:
Counts from 0 to 10 (given a time frame)
Avoid re-renders during count
Has proper controls:
Start: begin counting
Pause: stop temporarily without resetting
Reset: stop and reset to 0
React Code
import {useRef} from "react"
const Counter=()=>{
//make three ref to store the states during re-renders
const intervalRef=useRef(null);
const displayRef=useRef(null);
const counterRef=useRef(0);
const startHandler=()=>{
//setting the interval
intervalRef.current=setInterval(()=>{
//check if count exceeds 10
if(counterRef.current>=10){
clearInterval(intervalRef.current);
return;
}
//incrementing the counter
counterRef.current=counterRef.current+1;
if(displayRef.current){
displayRef.current.textContent=counterRef.current;
}
}, 1000)
}
const pauseHandler=()=>{
clearInterval(intervalRef.current);
intervalRef.current = null;
}
const resetHandler=()=>{
clearInterval(intervalRef.current);
if(displayRef.current){
displayRef.current.textContent=0;
}
counterRef.current=null;
}
return(
<div className="counter-container">
<h2>React Counter</h2>
<p className="counter-value"><span ref={displayRef}>0</span></p>
<div className="button-group">
<button onClick={startHandler}>Start</button>
<button onClick={pauseHandler}>Pause</button>
<button onClick={resetHandler}>Reset</button>
</div>
</div>
)
}
export default Counter;
CSS code:
.counter-container {
background-color: #1e1e2f;
color: #e0e0e0;
font-family: "Segoe UI", sans-serif;
padding: 2rem;
max-width: 400px;
margin: 2rem auto;
border-radius: 12px;
text-align: center;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
}
.counter-value {
font-size: 3rem;
font-weight: bold;
margin: 1rem 0;
}
.button-group button {
background-color: #2dd4bf;
color: #1e1e2f;
border: none;
padding: 0.6rem 1.2rem;
font-size: 1rem;
font-weight: 500;
margin: 0 0.4rem;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s ease-in-out;
}
.button-group button:hover {
background-color: #14b8a6;
}
Wrap Up
Using useRef instead of useState in this counter:
Avoids unnecessary re-renders
Offers direct control over DOM and timers
Keeps your UI snappy and performance-optimized
This approach is great for non-UI state (timers, subscriptions, etc.), and it’s a good technique to have in your React toolbox.
Happy coding! If you have any questions or suggestions you'd like to explore further, feel free to drop a comment below.
See you in the next blog. Please don’t forget to follow me on:
Subscribe to my newsletter
Read articles from Nitin Saini directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Nitin Saini
Nitin Saini
A Full Stack Web Developer, possessing a strong command of React.js, Node.js, Express.js, MongoDB, and AWS, alongside Next.js, Redux, and modern JavaScript (ES6+)