The Best Guide to the useEffect Hook in ReactJS

useEffect hook

Have you ever heard of react lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount? When we write class components in React, we use React lifecycle methods.

Now in the functional component, we can not use those methods, right? then how do we go forward? Thanks to the ReactJS team, they came up with a React Hook called useEffect hook.

But wait. is it the same as react lifecycle methods in the class component? The answer is NO. But using the React useEffect hook we can achieve all things that we achieve using react lifecycle methods. Here is a brief article about the useEffect react hook which will help you to understand this hook in detail.

What is the useEffect Hook?

Many would say that the useEffect hook is used to perform side effects in your react component. But now one will tell what is meant by side effects in your component.

In simple language, side effects mean everything apart from the UI part of the component. Suppose you want to fetch a data from third-party URL, subscribe to any event, or perform a DOM manipulation, all these are side effects.

Why useEffect hook is necessary in react?

If you try to fetch data without using the useEffect hook, you will face an infinite loop of calling API which will ultimately crash your application. When your component renders, the useEffect hook automatically gets called and performs side effect tasks.

Always remember, when you face the problem of the infinite calling of API, you should check your useEffect function in that particular component.

How to Use the useEffect Hook

Now we know what is useEffect hook and its use, let’s see how to use the useEffect hook in the react functional component.

useEffect(() => { 

// your logic => 1.Call API 2.DOM Manipulation 3.Event Handling

}, [dependencies]);

The first thing you see in the above snippet is the useEffect hook which takes two arguments.

The first is a callback function where you will write your side effect logic and the second is a dependency array. I will explain both the callback function and dependency array below in detail.

The Callback Function in useEffect hook

The callback function is used as a first argument in the useEffect hook. In that, we write side effect logic like calling API using fetch / Axios, DOM manipulation, or event handling. Here we don’t need to no what is callback function in detail.

useEffect(() => {

  // fetch data from external API
  const fetchData = async () => {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    setData(data);
    // do something with the data
  };

  fetchData();
}, []);

In the above example, we can see a fetchData() which is an asynchronous function inside a useEffect callback function.

It will fetch the data from the respective API and data will be saved to the component state using the useState hook. This fetchData() will be invoked as soon as your component renders and fires only a single time (important).

The Dependency Array in useEffect hook

The dependencies array is an optional argument in the useEffect hook. It allows you to control when the side effects should be executed. The useEffect hook will only be called again if one of the values in the dependencies array changes.

Now let’s understand the second useEffect argument, dependency array. This hook really depends on this argument. It is an optional argument, if you keep the array blank [ ], no problem. It means it does not depend on any state.

useEffect(() => {

  // your side effect logic

}, [dependency1, dependency2]);

But if you specify some things in that array (like state), then your side effect logic will trigger whenever the value of those things (or state) changes.

This dependency array helps you to avoid unnecessary re-renders and optimize the performance of the component. You can have multiple values in a dependency array without any problem.

Below I have written one example, which is calling an API with with variable ‘useInput’. Now you don’t want to call this API unless there is a new userInput, right? so, we added ‘useInput’ in the dependency array.

useEffect(() => {
  // fetch data from API based on user input
  const fetchData = async () => {

    const response = await fetch(`https://api.example.com/data?input=${userInput}`);
    const data = await response.json();
     setData(data);
    // do something with the data
  };
  fetchData();

}, [userInput]);

  //change in useInput will invoke the useEffect hook

So now whenever a user changes its input, it will automatically call this API. This means it will avoid unnecessary calls to API with the same userInput.

An Empty Dependencies Array

Suppose you don’t have any dependency to add and you want to fire side effect logic only once when the component renders, then you keep the dependency array blank.

It will help you when you want to show some API content without any complex operations in the component.

useEffect(() => {

  // side effect logic

}, []);

Play with this feature so you will understand more about it.

Cleanup function in useEffect

To clean up side effects, you can return a cleanup function from the useEffect callback. This function will be executed before the next side effect is called or when the component is unmounted.

Some side effects require a cleanup of the memory when the dependencies change. let’s take an example of setTimeout() function, if  setTimeout() is executed twice or more times, it will create a conflict and you won’t get the expected result. So we need to remove or clean the old setTimeout() to run the new setTimeout().  This means cleanup will remove the old data for the next render. It will help to prevent the memory leak and increase the performance of the component.

useEffect(() => {

  // side effect logic

  // return cleanup function
  return () => {

    // cleanup side effect
  };
}, [dependency]);

For this cleanup process, we define one cleanup function inside the useEffect callback back function. It will be returned at the end of the callback function.

The cleanup function will be called when the value of the dependencies changes. Hope you understand the cleanup function by now.

Read About: React useReducer hook – A complete guide for beginners

Common Mistakes while using useEffect hook

A lot of new developers or some experienced developers make some common mistakes while using the useEffect hook. Let’s see what are those common mistakes and how to avoid them.

Missing Dependencies Array

One of the most common mistakes new developers make is they forget to add a dependency array in the useEffect hook which is a second argument.

useEffect(() => {
  // side effect logic
});

This leads to performance issues and could cause harm to side effect operations. So always remember to add a dependency array w/ or w/o dependencies.

Infinite Loops

A similar mistake developers make is they use setState to update a state in the callback. But they forget to add a dependency array.

useEffect(() => {
  // update state
  setState(newState);
});

Not adding a dependency array while you are using setState() causes the infinite re-rendering of the component. This leads to the application crash.

To fix this infinite loop problem, make sure to include the necessary dependencies in the dependency array or you can simply add blank dependency array.

useEffect(() => {
  // update state
  setState(newState);
}, [dependency]);

Conclusion

We can here conclude that useEffect is one of the most important and used hooks in a ReactJS library. It helps us to run side effects in the components efficiently which ultimately increases the performance of the application.

While using the useEffect hook always remember to add a dependency array and cleanup function to avoid any negative effect on the component.

I hope this article helped you to completely understand the react useEffect hook. Now you can implement this hook in your project efficiently. Share this article with your friends, so they can also lean about this hook.

Happy coding!