Published: December 29, 2022 • 4 min read
Have you ever wanted to create a timer in a React app? In this post, I’ll
explain how to create a timer effect in a React application using hooks and
setInterval
.
Let’s get right to the code. Below, I’ll explain what every line is doing.
import React, { useState } from "react";
const App = () => {
const [timer, setTimer] = useState(undefined);
const toggleTimer = () => {
if (timer) {
clearInterval(timer);
setTimer(undefined);
} else {
const timerId = setInterval(() => console.log("tick"), 1000);
setTimer(timerId);
}
};
return <button onClick={toggleTimer}>{timer ? "Stop" : "Start"}</button>;
};
export default App;
Here’s the summary: this code creates a button that reads “Start”. On click,
that changes to “Stop”, creating a timer with setInterval
that ticks every second. This tick behavior could represent anything,
including:
Let’s start reading at return
. There, we have a button that shows a stateful call
to action.
import React, { useState } from "react";
const App = () => {
const [timer, setTimer] = useState(undefined);
const toggleTimer = () => {
if (timer) {
clearInterval(timer);
setTimer(undefined);
} else {
const timerId = setInterval(() => console.log("tick"), 1000);
setTimer(timerId);
}
};
return <button onClick={toggleTimer}>{timer ? "Stop" : "Start"}</button>;};
export default App;
Okay, what’s that state? It’s a timer
, and it’s initially undefined
:
import React, { useState } from "react";
const App = () => {
const [timer, setTimer] = useState(undefined);
const toggleTimer = () => {
if (timer) {
clearInterval(timer);
setTimer(undefined);
} else {
const timerId = setInterval(() => console.log("tick"), 1000);
setTimer(timerId);
}
};
return <button onClick={toggleTimer}>{timer ? "Stop" : "Start"}</button>;
};
export default App;
More on that in a second!
Click the button, and we call the function toggleTimer
. Because timer
starts as undefined
, our if
statement is falsy. So, let’s read the
else
.
import React, { useState } from "react";
const App = () => {
const [timer, setTimer] = useState(undefined);
const toggleTimer = () => {
if (timer) {
clearInterval(timer);
setTimer(undefined);
} else { const timerId = setInterval(() => console.log("tick"), 1000); setTimer(timerId); } };
return <button onClick={toggleTimer}>{timer ? "Stop" : "Start"}</button>;
};
export default App;
Here we call setInterval
, passing our ticking function and a delay of 1,000
milliseconds (that’s one second for the history majors). Every second, our tick
fires.
setInterval
has a useful return— an identifier for itself. This will be a
numeric non-zero value like 2202
. We’ll need that later to stop the tick, so
we save it with setTimer
.
Having timer
in state can be really handy; anytime we want to know if the
world is advancing, or the stopwatch is running, or whatever, the existence of
timer
can answer that question for us. That’s how we’re changing the call to action
from “Start” to “Stop.”
What happens the next time we call the function? timer
is truthy, so we
execute the if
:
import React, { useState } from "react";
const App = () => {
const [timer, setTimer] = useState(undefined);
const toggleTimer = () => {
if (timer) { clearInterval(timer); setTimer(undefined); } else {
const timerId = setInterval(() => console.log("tick"), 1000);
setTimer(timerId);
}
};
return <button onClick={toggleTimer}>{timer ? "Stop" : "Start"}</button>;
};
export default App;
Here, we use that same identifier, 2022
, to clear the timer. And, we set its
value in state to undefined
.
What if we want this timer to be running without user interaction? useEffect
accomplishes this nicely.
import React, { useEffect } from "react";
const App = () => {
useEffect(() => {
const timerId = setInterval(() => console.log("tick"), 1000);
return () => {
clearInterval(timerId);
};
}, []);
return <div />;
};
export default App;
We no longer need a state variable to store our timerId
because useEffect
has that in scope. Note the function we return, which makes sure the interval
is cleared when the component unmounts.
import React, { useEffect } from "react";
const App = () => {
useEffect(() => {
const timerId = setInterval(() => console.log("tick"), 1000);
return () => { clearInterval(timerId); }; }, []);
return <div>Timer</div>;
};
export default App;
That’s all there is to it! I hope you can build upon this simple example. To see this in action, check out the source code to my Conway implementation.
What are your thoughts on this? Let me know!
Get better at programming by learning with me! Join my 100+ subscribers receiving weekly ideas, creations, and curated resources from across the world of programming.