Implement a Timer Component – React Interview Question

I have gotten this problem twice in my React interviews.

What’s the problem statement?

Create a timer application which increments by 1 in intervals of 1 second, with 3 buttons on the UI: Play, pause, stop.

So let’s begin. You can use CodeSandbox to write your code.

Thought Process

We have to show a count which will increase on the intervals of 1 second. And we have to create 3 buttons (play, pause and stop) on the page.

On clicking play button, the timer will increment by 1 after 1 second. We will use setInterval for this.

Also, we will have a state variable isRunning to check if our timer is running or not.

Steps

1. Show the timer count

2. Check if the timer is running or not

3. Increment count in the timer with setInterval

4. Create Play, Pause, Stop buttons and attach onClick handlers

1. Show count

We want the count value (the value of the actual timer) to change after 1 second, so we will store this in a state variable.

const [count, setCount] = useState(0);

We can show the count using any HTML element.

{count}2. Check if the timer is running or not

This isRunning variable will take care of any user interaction on the 3 buttons that we will create later.

const [isRunning, setIsRunning] = useState(false);

So that we can use this later in our useEffect hook.

3. Increment count in the timer with setInterval

We could actually just use the setInterval method to run a timer.

And when we are initiating any kind of timer in React, we need to clean it up to remove any stale memory. And to clean it up, we will need to store the timer in some kind of a variable.

So, could we just do it like this?

let timerId;

No.

Because when the functional component re-renders, the timerId variable will re-declare and lose its previous value, so we cannot clear the timer interval reliably.

To persist the value of timerId, we will just use the useRef hook from React.

let timerId = useRef(null);

And we will put the code related to setInterval in a useEffect hook by taking isRunning inside the dependency array.

useEffect(() => {
timerId.current = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);

return () => {
clearInterval(timerId.current);
};
}, [isRunning]);

In the above code, notice that the timer will start even if isRunning is false. That means, it will start running even without the user initiating any click or interaction on the page. 

We don’t want this.

To fix it, wrap the code that starts the timer, inside an if statement, checking if the timer is started by a user interaction.

useEffect(() => {
if (isRunning) {
timerId.current = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
}

return () => {
clearInterval(timerId.current);
};
}, [isRunning]);4. Create Play, Pause and Stop buttons
Play


Pause


Stop
a. Play button

Hitting the play button will simply initiate the timer. And for that we can just update the value of isRunning to true.

const playTimer = () => {
setIsRunning(true);
};

So when the value of isRunning changes to true, the useEffect will run and the timer will start.

b. Pause button

Clicking the pause button will stop the timer. For that, we can just update the value of isRunning to false.

const pauseTimer = () => {
setIsRunning(false);
};c. Stop button

Firing the stop button will stop the timer as well as bring the count to 0.

const stopTimer = () => {
setIsRunning(false);
setCount(0);
};d. Attach the functions to all the 3 buttons
Play


Pause


Stop

I have added a value for the disabled attribute on each of the buttons for better UX.

Full Codeimport { useEffect, useRef, useState } from "react";
import "./styles.css";

export default function App() {
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(false);
let timerId = useRef(null);

useEffect(() => {
if (isRunning) {
timerId.current = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
}

return () => {
clearInterval(timerId.current);
};
}, [isRunning]);

const playTimer = () => {
setIsRunning(true);
};

const pauseTimer = () => {
setIsRunning(false);
};

const stopTimer = () => {
setIsRunning(false);
setCount(0);
};

return (

{count}

Play


Pause


Stop


);
}Output

Basic solution for this problem is completed. 

Now let’s improve this.

Improvement #1: Add a Continue button

For better UX, when the user clicks the pause button, the “play” button text can change to “continue”, so the user knows that the timer can be resumed from where it was paused.


{count > 0 ? "Continue" : "Play"}
Full codeimport { useEffect, useRef, useState } from "react";
import "./styles.css";

export default function App() {
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(false);
let timerId = useRef(null);

useEffect(() => {
if (isRunning) {
timerId.current = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
}

return () => {
clearInterval(timerId.current);
};
}, [isRunning]);

const playTimer = () => {
setIsRunning(true);
};

const pauseTimer = () => {
setIsRunning(false);
};

const stopTimer = () => {
setIsRunning(false);
setCount(0);
};

return (

{count}

{count > 0 ? "Continue" : "Play"}


Pause


Stop


);
}Subtle “bug”

Although a minor issue but if you notice, the continue button displays even when we have not clicked the pause button.

As soon as we click the play button and the count of the timer goes beyond 0, the continue button displays.

To fix this…

We only need to show the continue button once the pause button is clicked, and of course when count > 0

We can just create another state variable like isPaused 

const [isPaused, setIsPaused] = useState(false);

… and use it along with count > 0 to conditionally show continue or play button.

{count > 0 && isPaused ? "Continue" : "Play"}Clean versionimport { useEffect, useRef, useState } from "react";
import "./styles.css";

export default function App() {
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(false);
const [isPaused, setIsPaused] = useState(false);
let timerId = useRef(null);

useEffect(() => {
if (isRunning) {
timerId.current = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
}

return () => {
clearInterval(timerId.current);
};
}, [isRunning]);

const playTimer = () => {
setIsRunning(true);
setIsPaused(false);
};

const pauseTimer = () => {
setIsRunning(false);
setIsPaused(true);
};

const stopTimer = () => {
setIsRunning(false);
setIsPaused(false);
setCount(0);
};

return (

{count}

{count > 0 && isPaused ? "Continue" : "Play"}


Pause


Stop


);
}OutputImprovement #2: Add Reset button

Instead of “Stop” button, we can have a “Reset” button that will:

Stop the timerBring the count to 0Disable the reset button itself if the count is 0

This will provide a better user experience.

Note: Ideally, a stop button doesn’t bring the count to 0. It just stops the timer. Whereas, a reset button stops the timer as well as bring the count to 0.

Remove stop button
Reset
Function to reset the timerconst resetTimer = () => {
setIsRunning(false);
setIsPaused(false);
setCount(0);
};Full codeimport { useEffect, useRef, useState } from "react";
import "./styles.css";

export default function App() {
const [count, setCount] = useState(0);
const [isRunning, setIsRunning] = useState(false);
const [isPaused, setIsPaused] = useState(false);
let timerId = useRef(null);

useEffect(() => {
if (isRunning) {
timerId.current = setInterval(() => {
setCount((prev) => prev + 1);
}, 1000);
}

return () => {
clearInterval(timerId.current);
};
}, [isRunning]);

const playTimer = () => {
setIsRunning(true);
setIsPaused(false);
};

const pauseTimer = () => {
setIsRunning(false);
setIsPaused(true);
};

const resetTimer = () => {
setIsRunning(false);
setIsPaused(false);
setCount(0);
};

return (

{count}

{count > 0 && isPaused ? "Continue" : "Play"}


Pause


Reset


);
}OutputConclusion

This is how you can create an effective timer component in your React interviews.

Good luck!

Please feel free to provide any feedback to the above solution.

The post Implement a Timer Component – React Interview Question appeared first on Suman Sourabh.

 •  0 comments  •  flag
Share on Twitter
Published on October 04, 2025 12:15
No comments have been added yet.