A timer representing setTimeout inside of a React component

Use setTimeout in your React components to execute a function or block of code after a period of time. Let’s explore how to use setTimeout in React. There is also a similar method called setInterval, you can learn more about it from this guide

The TL;DR:

useEffect(() => { const timer = setTimeout(() => { console.log('This will run after 1 second!') }, 1000); return () => clearTimeout(timer); }, []);

What is setTimeout?

The setTimeout method calls a function or runs some code after a period of time, specified using the second argument.

For example, the code below prints “Hello, World!” to the developer console after 3,000 milliseconds (or 3 seconds).

setTimeout(() => { console.log('Hello, World!') }, 3000);

Using setTimeout in React Components

Using setTimeout inside of a React component is easy enough as it’s just a regular JavaScript method.

For instance, let’s use setTimeout inside of a functional React component which uses Hooks. We’ll call setTimeout inside of the useEffect Hook, which is the equivalent of the componentDidMount lifecycle method in Class components.

App.js
import React, { useEffect } from 'react'; const App = () => { useEffect(() => { const timer = setTimeout(() => { setCount('Timeout called!'); }, 1000); return () => clearTimeout(timer); }, []); return ( <div> Hello, World </div> ); }; export default App;

Our functional component runs the useEffect method when it first renders. If you want to learn more about Hooks, I recommend my tutorial on Simplifying Forms using React Hooks.

We schedule a new setTimeout called timer when the App component mounts for the first time.

As a result, the code inside of the setTimeout block runs after 1 second as indicated by the 1000 millisecond value that’s passed into the second parameter of the setTimeout method.

Clearing setTimeout

A setTimeout timer must be cleared and handle properly, otherwise, you may experience adverse side effects in your code.

To clear or cancel a timer, you call the clearTimeout(); method, passing in the timer object that you created into clearTimeout().

For example, the code below shows how to properly clear a timer inside of a functional React component.

App.js
... const App = () => { useEffect(() => { const timer = setTimeout(() => console.log("Hello, World!"), 3000); return () => clearTimeout(timer); }, []); }; ...

And an example of clearing setTimeout inside of a React Class component:

App.js
... class App extends Component { let timer = null; componentDidMount() { timer = setTimeout(() => console.log('Hello, World!'), 3000) } componentWillUnmount() { clearTimeout(timer); } } ...

Above all, it’s important that you clear timers, otherwise you could experience errors in your code.

You’ll notice that in the first example of clearing a timer inside of a functional component, we’re returning an anonymous function from the useEffect Hook. This is the equivalent of componentWillUnmount as shown in the second example.

setTimeout Gotchas

Using a state property inside of a setTimeout does not use the current value of that state property.

I found this odd issue with setTimeout and state when I was trying to access a state prop inside of setTimeout.

Take the example below:

TimeoutExample.js
import React, { useEffect, useState } from 'react'; const TimeoutExample = () => { const [count, setCount] = useState(0); const [countInTimeout, setCountInTimeout] = useState(0); useEffect(() => { setTimeout(() => { setCountInTimeout(count); // count is 0 here }, 3000); setCount(5); // Update count to be 5 after timeout is scheduled }, []); return ( <div> Count: {count} <br /> setTimeout Count: {countInTimeout} </div> ); }; export default TimeoutExample;

You would expect the value of countInTimeout to be 5, but it’s actually 0.

Huh?!

setTimeout is a closure, therefore, when setTimeout is scheduled it uses the value of count at that exact moment in time, which is the initial value of 0.

To solve this, use the useRef Hook:

function App() { const [count, setCount] = useState(0); const countRef = useRef(count); countRef.current = count; const getCountTimeout = () => { setTimeout(() => { setTimeoutCount(countRef.current); }, 2000); }; return ( ... ) }

This solution is thanks to a discussion on Github: https://github.com/facebook/react/issues/14010

Avatar photo
👋 Hey, I'm James Dietrich
James Dietrich is an experienced web developer, educator, and founder of Upmostly.com, a platform offering JavaScript-focused web development tutorials. He's passionate about teaching and inspiring developers, with tutorials covering both frontend and backend development. In his free time, James contributes to the open-source community and champions collaboration for the growth of the web development ecosystem.

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.