Accessing state in setTimeout React.js

We frequently deal with timeouts when developing different applications with React. A setTimeout method enables us to invoke a function after a particular interval. However, implementing the conventional setTimeout in React can be difficult. For the application to operate effectively, we need to keep track of timeouts inside the useEffect hook and clear them. The use of state variables in setTimeouts is a bit counterintuitive. setTimeouts do not use the current value of state properties.

In this article, we’ll look at how to access the state property in timeouts within react components.

Approach: Let’s begin by creating a counter application that displays a counter and has a button to increment it.

 

Creating React Application:

Step 1: Make a project directory, head over to the terminal, and create a react app named counter using the following command:

npx create-react-app counter

Step 2: After the counter app is created, switch to the new folder counter by typing the command below:

cd counter

Project Structure: We will modify the folder and keep the files we need for this example. Now, make sure your file structure looks like this:

Final Directory Structure  

Example: Follow the below approach and implement that in the react.js:

Approach: Creating a counter:

  • The useState hook defines a state inside a functional component. The count variable serves as the state variable, and the setCount function allows us to modify the count.
  • React will regenerate the setTimeout method each time the component is re-rendered, setting a new timeout. Therefore,  we must use the useEffect hook with an empty dependency array to create a timeout after the component mounts.
  • We will pass the logic and the delay argument inside the setTimeout method. 
  • After 3 seconds, the count will be console logged. 
  • We have a button to increment the count.

index.html: Include the following code in your index.html file, located in the public folder of your project directory. 

HTML




<!DOCTYPE html>
<html lang="en">
  
<head>
    <meta charset="utf-8" />
    <meta name="viewport" 
          content="width=device-width, initial-scale=1" />
    <meta name="theme-color" 
          content="#000000" />
    <meta name="description" 
          content="Web site created using create-react-app" />
    <title>Counter App</title>
</head>
  
<body>
    <div id="root"></div>
</body>
  
</html>


App.js: 

Javascript




import { useEffect, useState } from "react";
import './App.css';
  
function App() {
    const [count, setCount] = useState(0);
  
    useEffect(() => {
        setTimeout(() => {
            console.log(count);
        }, 3000);
    }, []);
  
    return (
  
        <div className="counter">
            <h2>{count}</h2>
            <button className="btn"
                onClick={() => setCount(count + 1)}>
                Press to increment the count
            </button>
        </div>
    );
}
  
export default App;


App.css: Add the following code to App.css to style the counter application.

CSS




.counter {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    border: 4px solid darkGreen;
    margin: 2rem;
}
  
.btn {
    font-size: 1rem;
    margin: 1rem;
    background-color: darkgreen;
    color: white;
    padding: 1rem;
    cursor: pointer;
    border-radius: 10px;
}


index.js: Add the following code to the index.js file. 

Javascript




import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
  
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
        <App />
    </React.StrictMode>
);


Step to run the application: Run the application by using the following command:

npm start

Output: By default, the React project will run on port 3000. You can access it at localhost:3000 on your browser. 

Output : Counter Application 

We will observe that 0 is console-logged after an interval of 3 seconds. 

Explanation: After three seconds, the value 0 will be logged into our console. Now, the counter’s current value may not be 0. The console should have displayed 2 if we had clicked the button twice to increment the counter before the timeout fired.

In reality, no matter how many times we update the count number, the inline callback is actually a closure function that points to the value of the counter at the moment of its creation when setTimeout is called. Thus, it will always display 0.

We can resolve this issue by using the useRef hook in our application. 

Accessing the state in timeouts:

  • In this example, we must establish a closure function around an object to access its current state. The object’s value is changed every time the counter function executes, while the reference to the object remains constant.
  • Using the useRef hook, we will create a reference object and pass the initial value of the counter to it. 
  • useRef returns an object having a property, i.e., current.
  • We will set the ref value by accessing the .current property of the reference object.
  • The countRef.current points to the current state value of the counter.
     

Example 2: Replace the previous code with the following code in the App.js file: 

App.js: 

Javascript




import { useEffect, useState, useRef } from "react";
import './App.css';
  
function App() {
    const [count, setCount] = useState(0);
  
    //creating a reference object
    const countRef = useRef(count);
    countRef.current = count;
  
    useEffect(() => {
        setTimeout(() => {
  
            //accessing the current state of the counter
            console.log(countRef.current);
        }, 3000);
    }, []);
  
    return (
  
        <div className="counter">
            <h2>{count}</h2>
            <button className="btn"
                onClick={() => setCount(count + 1)}>
                Press to increment the count
            </button>
        </div>
    );
}
  
export default App;


Step to run the application: Run the application by using the following command:

npm start

Output:

Final Output: Accessing the state in timeouts

We now have access to the counter’s current state in the timeouts. 

Whether you’re preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape, zambiatek Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we’ve already empowered, and we’re here to do the same for you. Don’t miss out – check it out now!

Related Articles

Leave a Reply

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

Back to top button