Using UseEffect Hook: Avoiding Excessive Re-rendering
Tags: react, hooks, useeffect
Published: 2023-04-19 11:23:25


React is one of the most popular front-end web development frameworks and has gained widespread adoption since its release in 2013. In React, there are two ways to define a component: class components and functional components. Functional components are widely used now-a-days because they are simpler and more lightweight than class components. To manage states and side effects, hooks are used in functional component which have made our works much easier.

UseEffect is one of the react hooks that allows functional components to perform side effects, such as fetching data or updating the DOM, in response to changes in state or props. But for the beginners, it may be somewhat troublesome. There are some common mistakes while using useEffect in code.


I have assumed that people reading this blog have already used useEffect hooks before. One of the simplest examples for showing useEffect hook is of increasing counter value and displaying the value in the webpage.

```
import {useEffect, useState} from "react";

function App() {
  const [count, setCount] = useState(0)

  useEffect(()=>
  {
    console.log("Rerendering!")

    setInterval(() => {
      setCount(count+1)
    },1000)
  },[count])

  return (
  <div>Current count is: {count}</div>
  )
}

export default App;

```
We have used the **useState** hook to define a state variable called **count** and a function called **setCount** which will be used to update the state of count. In this case, the initial value of count is set to 0.

The **useEffect** hook is used to handle side effects in functional components. In this case, it sets an interval using **setInterval** to update the **count** value every 1000ms (1 second). Whenever the **count** value changes, the **useEffect** hook is called again due to the dependency array **[count]**, and the component is re-rendered.

You can find the running code [here](https://codesandbox.io/s/react-useeffect-ex-1-h9fhrd).

After running the code, you will observe some abnormalities in the webpage. You will understand better if you open your console. It have been rendering infinitely. This has happened because the count is updating every second. Since the count is the dependency in our useEffect, it runs the function again and again. 

But a question can appear in your mind, why the number of Rendering printed on the console is more than the count. As we already know the function is run when the **count** is changed. This happens because the **setInterval** function is asynchronous, it is possible for multiple updates to be scheduled before the component has a chance to re-render. This means that there may be several updates to the count state variable before the component actually re-renders and displays the updated count. This is why you may see more log messages for "Rendering!" than the count updates you observe.

Now, to remove this infinite loop, we will now update the code a bit.

```
import { useEffect, useState } from "react";

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Rerendering!");

    setInterval(() => {
      setCount((prev) => prev + 1);
    }, 1000);
  }, []);

  return <div>Current count is: {count}</div>;
}

export default App;

```
Here, we pass an empty dependency array **[]** to the **useEffect** hook, which means that the effect will only run once on mount and not re-run on updates. We also use a **functional update** to update the count state variable inside the **setInterval** function, which ensures that we always have the latest value of count and avoids the infinite loop.
You can see the running code [here](https://codesandbox.io/s/jolly-cache-2dlbrq?file=/src/App.js).

This time the code runs almost perfectly. The re-rendering is seen on the log once or twice. It's supposed to be one. But because your **App** is wrapped inside **React.StrictMode**, it renders twice. **StrictMode** renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them (which can be quite useful). So, you may get 2 log messages of Rerendering!


![index.js](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w7el3rhgtunewfuqof6t.png)

Now, it is the time for making this piece of code perfect as we have said the previous one was almost perfect. The best practice of using useEffect is with a cleanup function.

```
import { useEffect, useState } from "react";

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    console.log("Rerendering!");

    const interval = setInterval(() => {
      setCount((prev) => prev + 1);
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  }, []);

  return <div>Current count is: {count}</div>;
}

export default App;

```

In this code, the **clearInterval** function is called inside the **cleanup** function that is returned from the **useEffect** hook. You can find the running code [here](https://codesandbox.io/s/beautiful-mcclintock-sd8u5v?file=/src/App.js:24-426).


The **useEffect** hook sets an interval using the **setInterval** function, which repeatedly updates the **count** state variable. Without a **cleanup** function, the interval would continue running even after the component is unmounted, leading to potential memory leaks and performance issues. The **cleanup** function ensures that the interval is cleared when the component is unmounted or when the count state variable changes and the effect is re-run.

Hope that now you all can write useEffect hooks without any confusion of excessive re-rendering. This is all for now. For any enquiries, let me know.