setTimeout in React Components Using Hooks

James King
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.

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, you can use the useRef Hook:

const countRef = useRef(count); countRef.current = count; const getCountTimeout = () => { setTimeout(() => { setTimeoutCount(countRef.current); }, 2000); };

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

Related Tutorials 👇

📮 Join the Upmostly Newsletter

Get one email a month, packed with our latest React tutorials, delivered straight to your inbox.
Zero spam, just great content. Unsubscribe at any time.

💬 Leave a comment

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

We will never share your email with anyone else.