React

useEffect: The Effect hook

We already have an idea about managing state using the react hook useState. Let’s try to understand the concept of the other...

Written by Shivangi Rajde · 5 min read >
UseEffect: The Effect hook

We already have an idea about managing state using the react hook useState. Let’s try to understand the concept of the other hooks that are useEffect. Till now the main reason that attracts us for using the class components instead of functional components is that we can use the lifecycle methods in the class components. What if we have a solution for that too for using in functional components?

Why do we require useEffect Hook?

Let’s imagine that we have multiple components that we simple when started building it but has now grown to complex and unmanageable code with stateful logic and side effects. When working with class components we have certain methods known as lifecycle hooks that get called at certain points.

The Effect Hook

The effect hook is used to provide effects to our functional components. As compared to the class component the effect of the useEffect hook will be the same as the componentDidMount, componentWillMount, and shouldComponentUpdate.

The meaning that we can use the method similar to the lifecycle methods of class components doesn’t mean that we can write componentDidMount, componentWillMount, and other lifecycle methods inside the functional component.

useEffect(()=>{ 
//called on every re-render. Called on component update, mount and unmount 
   return function ( ) { 
       //called when the component unmounts 
       //used for clean-up 
       }
    }, 
[                            //second Parameter 
   Value(s)                  //monitored value 
] 
) 

The second parameter is passed for conditional rendering. To understand that there are few scenarios which tell us the possible ways to use that.

There are multiple scenarios that will make it easier for you to understand the importance and functionality of the second parameter with the help of the example from the demo.

There are three ways in which we can execute the useEffect hook’s code that allows us to perform operations at different points of time in the component.

  • The component renders first time (only when loads)
  • The component renders for the first time and at the time of re-render.
  • The component renders for the first time and at the time of re-rendering some data changes

To use useEffect hook in our component we need to import that from react.

Let’s understand the structure of useEffect hook.

The first argument of the useEffect will be a function that will contain the code for performing the side effects to our component. The second argument is an array that helps us to control the point of time when we want to execute our useEffect code.

Please note that it is not necessary to have the arrow function as the first argument of the useEffect hooks, we can also use the function keyword to define the function as per our convenience.

Moving towards the scenarios for executing our code at different points of time as per our requirement.

Second argument as an empty array

useEffect(() => { 
    console.log(`You clicked ${count} times`); 
  },  
 [ ])            //reason for being called only once, similar to componentDidMount 

If we pass an empty array it means that the useEffect will be called only on the initial render. In other words, if we pass an empty array, it means that we are not interested in monitoring any of the values so that the useEffect won’t be called except on mounting and before unmounting. This mimic’s the working of componentDidMount and componentWillUnmount, it will only run once.

If we want to check that is it actually called only called on the initial render then let’s add one more console log above the useEffect hook.

As you can see in the image below that the console that we have added renders every time when anything is updated in the component. The console line added above the useEffect hook is called every time we click on the button that updates the “count” value but the message in the hook is only printed once on the initial render of the component.

Second argument as an array with some values

useEffect(() => { 
    console.log(`You clicked ${count} times`); 
}, [count]);
//function inside useEffect will be called every time "count" updates 

The value passed as the second parameter (array) here in our example: count will be responsible for the execution of the function inside the useEffect Hook. If the value inside the array will be updated, then and only then the function will be executed.

What if we have multiple useEffect hooks and we need to update just a few of them? Conditional rendering comes in light. Conditional rendering is achieved by passing the second parameter instead of just an empty array. The values in the array will be monitored and the useEffect function will only be called when the monitored value(s) is/are updated.

As we can see that the console that we have added in the useEffect’s first argument that is a function gets printed whenever “count” updates that is our value in the second parameter.

As per react’s documentation, if you use this optimization, make sure the array includes all values from the component scope (such as props and state) that change over time and that are used by the effect. Otherwise, your code will reference stale values from previous renders.

If you want to run an effect and clean it up only once (on mount and unmount), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run. This isn’t handled as a special case — it follows directly from how the dependencies array always works.

If you pass an empty array ([]), the props and state inside the effect will always have their initial values. While passing [] as the second argument is closer to the familiar componentDidMount and componentWillUnmount mental model, there are usually better solutions to avoid re-running effects too often.

Missing Second argument

useEffect(() => { 
    console.log(`Printed on initial render and on every re-render.`); 
}); 

In the last scenario, we only have a single argument in our useEffect hook, it also means that we have removed the second argument which is not even an empty array. In this case, when the second argument is missing the function passed in our useEffect will run initially that is when the component renders and it would run every time our component re-renders.

We have a single argument passed in our useEffect hook. We have multiple states used in our component which change on various events for example our text state is used to maintain the value of our input field, the count is used to track the number of clicks on the button, and click on another button changes the value of other states “fruit”.

Let’s try to make various events that change any of the states of our component.

Entering some value in the textbox and clicking the button to increment the count runs the function of the useEffect hook irrespective of the event occurring, the function gets executed whenever any of the prop or state updates.

In this scenario it doesn’t seem that it can cause a problem but imagine when working with real-time projects there would be many more props and states to be managed at that point of time it can be a reason for multiple renders, lagging of our application, innumerable API calls, infinite loops, etc keeping in mind all these points adding the second argument should not be ignored.

Possible errors

There are some problems that may occur, for example, your program will go to an infinite loop as our useEffect hook doesn’t monitor any value(s). This condition can occur if we don’t pass the second argument and set the state variable inside the useEffect hook. This happens as at the time of rendering useEffect will be called and when the function will be executed set function of useState will be called inside it, so this scenario will lead to an infinite loop. If there is no second argument provided the useEffect() will fire on every update no matter what is being updated. Even further, if there’s a setState() or a useState() setter being used inside – useEffect() will go into an infinite loop.

Summary

After reading this article we have a clear understanding of the useEffect hook. There are multiple ways in which the useEffect hook can be utilized and various scenarios where we can use the useEffect hook for different purposes. We also have an idea about possible errors that we can face while using the useEffect hook.

To read more about hooks refer to the links given below:
useState: Managing State in React functional components

useTransition Hook

Loading

3 Replies to “useEffect: The Effect hook”

Leave a Reply

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