How to Properly Use setTimeout in React

Ferenc Almasi • 2022 September 09 • 📖 4 min read

In order to properly call setTimeout in React (and ensure it is only called once), you need to wrap your call inside a useEffect hook:

useEffect(() => {
    const timeout = setTimeout(() => {
        console.log('Called after 1 sec!')
    }, 1000)
 
    return () => clearTimeout(timeout)
}, [])
Copied to clipboard!

If you were to call the setTimeout outside a useEffect hook anywhere in your component, then this would rerun on every render.

Another important step is to always clear the timeout after the component unmounts, which you can do by returning a function from the useEffect hook. This is the equivalent of using componentWillUnmount in a class-based component.

Here we can call the clearTimeout function and pass our reference to the setTimeout in order to properly free up memory and remove the timeout.

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
JavaScript Course

Using State in setTimeout

Using state with setTimeout can sometimes be tricky. Imagine you have an input field with a submit button that delays the action by 1 second using a setTimeout.

import { useState } from 'react'

export default function App() {
    const [email, setEmail] = useState('')

    const submit = () => {
        setTimeout(() => {
            console.log(email)
        }, 1000)
    }

    return (
        <div>
            <input onChange={event => setEmail(event.target.value)} />
            <button onClick={submit}>Submit</button>
        </div>
    )
}
Copied to clipboard!

If you fill in the input and click on submit, then the value of the input will be logged to the console after one second, just as expected. But what happens if you update the input field after you clicked the button?

In this case, you will still get the value logged, but not the latest value. You will get the value logged out that was available in the input when you clicked on the button. In order to get around this, we need to use refs. Take a look at how our component changes now:

import { useRef, useState, useEffect } from 'react'

export default function App() {
    const emailRef = useRef('')
    const [email, setEmail] = useState('')

    useEffect(() => {
        emailRef.current = email
    }, [email])

    const submit = () => {
        setTimeout(() => {
            console.log(emailRef.current)
        }, 1000)
    }

    return (
        <div>
            <input onChange={event => setEmail(event.target.value)} />
            <button onClick={submit}>Submit</button>
        </div>
    )
}
Copied to clipboard!

We introduced a new ref using the useRef hook, and assign its current value to email inside a useEffect hook. Notice that you also want to add email as a dependency inside the dependency array.

Now inside the setTimeout, we log out emailRef.current instead of email. This way, you will always have the latest value available to you even inside the setTimeout.


Creating a useTimeout hook

Lastly, let's take a look at how you can create a useTimeout hook that you can later reuse inside your other components.

export const useTimeout = (callback, timeout) => {
  useEffect(() => {
    const timeoutReference = setTimeout(callback, timeout);
 
    return () => clearTimeout(timeoutReference);
   }, [])
}
Copied to clipboard!

This hook expects a callback function as well as a timeout, just like setTimeout, but it is wrapped inside a useEffect hook in order to ensure we only call it once. The hook also ensures that the timeout is cleared after the component unmounts. To use it inside a component, you can call it like so:

import { useState } from 'react'
import { useTimeout } from '@hooks'

export default function App() {
    useTimeout(() => {
        console.log('Called after 1 sec!')
    }, 1000)

    return ...
}
Copied to clipboard!
JavaScript Course Dashboard

Tired of looking for tutorials?

You are not alone. Webtips has more than 400 tutorials which would take roughly 75 hours to read.

Check out our interactive course to master JavaScript in 5 hours.

Learn More

📚 Get access to exclusive content

Want to get access to exclusive content? Support webtips with the price of a coffee to get access to tips, checklists, cheatsheets, and much more. ☕

Get access Support us
Read more on
🎉 Thank you for subscribing to our newsletter. x