Mastering React's useEffect Hook: A Comprehensive Guide
Tags: webdev, react, frontend, javascript
Published: 2023-03-30 01:14:27

## Introduction of useEffect Hook
The `useEffect` hook is a powerful tool that was introduced in React 16.8 as a part of the Hooks API. It allows developers to perform side effects, such as updating the DOM, fetching data, and subscribing to events in function components. Prior to `useEffect`, class components were used to handle such side effects, but with Hooks, developers can achieve the same functionality without having to write a class. The `useEffect` hook is versatile and can be used for a wide range of tasks, making it a popular and important feature in React development.

In this article, you will learn about the `useEffect` hook and how you can use it in your React Application. You will use a function component because React Hooks don't work inside classes.


## Prerequisites

Understanding this article requires the following:
- Installation of [Node.js](https://nodejs.org/en)
- Basic knowledge of JavaScript and React 

## Get Started
Use  `yarn create vite <project-name>` to create a new React project. Vite is used because it is fast in development and build times of React applications.

Start the application by running the following command:

```javascript
cd project-name
yarn run dev
```

## UseEffect Hook syntax and default behaviour



`useEffect` is a function which accepts two parameters, a callback function and a dependency array. To create a side effect with `useEffect` hook in your project, import the hook inside the functional component to access the states and props without writing additional code. 
`useEffect` by default runs after every render. It runs both after the first render and also after every update.
Here is an example of how to declare a `useEffect` hook in a functional component:

```javascript
// App.js

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

const App =()=> {
  const [count, setCount] = useState(0)
  
  useEffect(()=>{
    console.log(count);
  })

  return (
    <div style={{textAlign: "center", marginTop: "90px"}}> 
      <button onClick={() => setCount(prevCount => prevCount + 1)}>Increment Counter       </button>
      <h1>This is {count} </h1>
    </div>
  )
}
export default App;
```
The code snippet above does the following:

-  Imports `useEffect` and `useState` from React
- Creates a state variable with its corresponding set function and initiates the state with `0` as a value
- Add a button with a click handler to increment the count by passing in a function to update the previous state whenever the button is clicked
- Call the `useEffect` function within the component and pass in the function, which is executed after every render of the components 


## Preventing infinite loops in useEffect Hook

`useEffect` runs after every render and can cause an infinite loop when it renders, which in some cases, could lead to performance issues. To prevent this, you need to conditionally run the `useEffect` Hook from a functional component and provide the second parameter called "the dependency array" when you call the `useEffect` function.
The dependency array usually contains values that, if the value changes from one render to the next, it will cause the `useEffect` to run. This helps limit the number of times the effect runs and determines when it will run instead of running after every render.

```javascript
// App.js
... 
  useEffect(()=>{
    console.log(count);
  }, [])
...
```
In the code above, the `useEffect` function contains an array as its second parameter, called a dependency array.

An empty dependency array denotes that the function will run first for once when the components load, and there is no dependency to watch and trigger the effect to run again.

You can run the `useEffect` function every time `count` changes by adding `count` to the dependency array, as shown below:



```javascript
// App.js
... 
  useEffect(()=>{
    console.log(count);
  }, [count])
...
```
In the code above, when the component runs for the first time, the state starts at an initial value of `0`, and anywhere the `count` is called, the value is replaced with `0`, including the dependency array. Clicking the **Increment Counter** button manually triggers a re-render of the component and updates the state `count` from `0` to `1`, and all the `count` values are updated to `1` wherever it is used in the function

In the code snippet below, you will fetch meme images from the [meme API](https://api.imgflip.com/get_memes) and display a new image whenever a button clicks. You can use `useEffect` to fetch data from a server and display it without problems. Once the component is rendered, it will fetch and render the data. 

```javascript
// Meme.js

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

const Meme = () => {
  const [memeData, setMemeData] = useState({randomImage: "http://i.imgflip.com/1bij.jpg"});
  const [allMemeImages, setAllMemeImages] = useState([]);

  useEffect(() => {
    fetch("https://api.imgflip.com/get_memes")
      .then((res) => res.json())
      .then((data) => setAllMemeImages(data.data.memes));
  }, []);

  const handleClick = () => {
    const randomNum = Math.floor(Math.random() * allMemeImages.length);
    const url = allMemeImages[randomNum].url;
    setMemeData((prevState) => {
      return {
        ...prevState,
        randomImage: url,
      };
    });
  };

  return (
      <div style={{ textAlign: "center", marginTop: "90px" }}>
        <button onClick={handleClick}>Get a new meme image</button>
        <div style={{ textAlign: "center", marginTop: "90px" }}>
          <img
            src={memeData.randomImage}
            alt='meme-images'
            style={{ width: "300px", height: "300px" }}
          />
        </div>
      </div>
  );
};
export default Meme;
```
The code above does the following:

- Import `useEffect` and `useState` from React
- Declares the initial state for `metadata` to display an image on the first render of the component with `setMemeData` as the set function
- Declares the initial state for `allMemeImages` to store all the images from the meme API endpoint
- `useEffect` hook is called, and the fetch function is used to make a call to the meme API and store all the data using the `setAllMemeImages`. An empty dependency array indicates that the meme API is called once with the `useEffect` hook 
-  Declares `handleClick` function to get a new image when the button is clicked. This function randomly generates a URL from the list of all the image URL gotten from the meme API and stored in the `allMemeImages` state. In this function, `setMemeData` is used to re-render the component on every click, which makes the image change to another image on the screen

To display the application on the browser, import the `Meme.js`  file inside the `App.js` file, as shown below.

```javascript
//App.js

import React from 'react'
import Meme from './Meme.js';
const App =()=> {
  return (
   <Meme />
  )
}
export default App;
```
At this point, your application should look like the following:

![final result](https://media.giphy.com/media/v1.Y2lkPTc5MGI3NjExYTdiZGUwYzMxMTlmNTU4MzQ5N2JmNDc5YWNiOTJhZDhjYTIyNDI4OCZjdD1n/G1jH1mAyjSRUAiCbbz/giphy.gif)


## Conclusion

This article discusses `useEffect` hook and how you can use it in your React Application to call API endpoints. It explained the default behaviour of `useEffect` and how you can prevent infinite loops while using `useEffect` hook.
Follow the resources below to learn more about `useEffect` hooks.

## Resources
- [A Complete Guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)
- [Using the Effect Hook](https://react.dev/reference/react/useEffect)