Explaining useEffect Hook in React

Share your love

useEffect hook is one of the most used hooks in React and it specializes in performing side effects in Functional Components.

After the introduction of hooks in React V-16.8, many things that were done by class components which led to many complex situations were solved very easily and tidily.

In this blog, we will mainly discuss the useEffect hook which very easily has replaced all the three lifecycle methods when it comes to performing side-effects.

Index

  1. What is useEffect Hook
  2. Types of side-effects
    • Side-effects without Cleanup
    • Side-effects with Cleanup
  3. Syntrax
  4. Different cases of useEffect Hook
    • Without dependency array
    • With empty dependency array
    • With state or prop in the dependency array
  5. Conclusion

What is useEffect Hook?

As told, it is used to perform side effects in Functional Components. Side Effects are nothing but actions performed by the functional components that do not affect the output of the Component like fetching data, manipulating DOM, etc.

Let’s see a basic example to understand it better – 

We will be making a counter as we did in the case of useState hook

import React, { useState } from "react";

const Practise = () => {
  const [count, setCount] = useState(0);

  return (
    <>
      <div>
        <p>You clicked {count} times</p>
        <button onClick={() => setCount(count + 1)}>Click me</button>
      </div>
      );
    </>
  );
};

export default Practise;

This is a basic code for updating a counter whenever the button is clicked. This is the perfect example to understand the useState hook, and now it will become the perfect example to understand the useEffect hook.

There are two kinds of side-effects that the useEffect hook performs – 

  1. Effects without Cleanup
  2. Effects With Clean-

Side-Effects of useEffect Hook without Cleanup

Side-Effects like DOM manipulation, Network Requests come under this category of effects. 

According to the official documentation, “Effects without cleanup are those effects which we only have to use once and then forget about as it will always render itself as the component re-renders.

An example might be useful here –

import React, { useState } from "react";

const Practise = () => {
  const [count, setCount] = useState(0);

    useEffect(() => {
      document.title = `You clicked ${count} times`;
    });

  return (
    <>
      <div>
        <p>You clicked {count} times</p>
        <button onClick={() => setCount(count + 1)}>Click me</button>
      </div>
      );
    </>
  );
};

export default Practise;

In the previous code, we have updated the state brilliantly, but we want it to show the result as the title of the page, this is what we call a side-effect as it is not affecting the output in any way.

There are certain rules for calling hooks and according to it useEffect hook should always be called after the useState hook as it will keep the code clean and easy to read by the browser, if done otherwise, the console will give us an error, and we can’t code further. For more information about rules that we have to follow click here

This hook accepts a callback function as its first argument and will run those side-effects with it that we have wished for or coded.

We know that hooks remember the states that have been used throughout the component giving us the ability to use the state anywhere inside the component.

The same case is with this hook, rather than remembering states, it remembers effects or the function as it is one. This function will be called after the DOM is done with updating itself

In the above code, we want to change the title of the document with every state change. This is only possible in the case of hooks, especially useEffect hook.

Example of useEffect Hook
example of useEffect Hook

Now, if we compare this to our good old class components – 

import React, { Component } from "react";

export class Practise extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

export default Practise;

The side effects have been put inside both componentDidMount and componentDidUpdate lifecycle methods.

This is because sometimes we have to perform the same side-effects whether the component has been mounted or updated or not. But, in-class components, side-effects cannot be performed after every render or after every DOM update.

This is where hooks have an advantage over class components.

Have you noticed that we have used the state variable inside the function of the hook? This will cause the value of the function to change every time the component is rendered like if we increase the by 1 in the counter, the title will also change. This is intentional, as it lets us read the value of state without getting it stale, and because of which we get a new value after every render or state change.

Side-Effects of useEffect Hook with Cleanup

As the name suggests, it is a hook similar to componentWillUnmount lifecycle as it helps in the cleanup if there is a memory leak in our App.

Let’s understand this with an example. In the previous example, we have to repeat the same piece of code twice. But here there are three of them, so it will repeat three times, one for every lifecycle method, and again it will respond once.

But not in the case of useEffect hook, it renders whenever there is a change in the DOM or state if it’s been used as a callback function inside useEffect.

In the case of the useEffect hook, we can just say that they are so well connected to each other that React simply knows when it’s time to unmount the component as it is created in such a way.

Now the question is, will it do the cleanup after every render as useEffect runs and gets updated after every render. The answer is YES!, it will. This is the main reason why after every renders previous effects are not there.

Unlike componentDidMount or componentDidUpdate, effects scheduled with useEffect don’t block the browser from updating the screen. This makes your app feel more responsive.

The majority of effects don’t need to happen synchronously. In the uncommon cases where they do (such as measuring the layout), there is a separate useLayoutEffect Hook with an API identical to useEffect.

Syntax

Like useState hook, it also accepts two arguments one of which is a callback function as we have already discussed, and the other accepts dependencies like an array. The syntax is as follows – 

useEffect(callback function, [dependencies]);

Different cases of use4Effect Hook

1. If the dependency array is not there

import { useEffect } from 'react';
function MyComponent() {
 useEffect(() => {
   // Runs after EVERY rendering
 }); 
}

In this case, side-effect runs only when the component re-renders

2. If the dependency array is empty

import { useEffect } from 'react';
function MyComponent() {
 useEffect(() => {
   // Runs ONCE after initial rendering
 }, []);
}

Here, side-effects will run once only after the initial rendering and will not get updated even if the component re-renders or the DOM changes.

3. If there is either state or prop or both in the dependency array

import { useEffect, useState } from 'react';
function MyComponent({ prop }) {
 const [state, setState] = useState('');
 useEffect(() => {
   // Runs ONCE after initial rendering
   // and after every rendering ONLY IF `prop` or `state` changes
 }, [prop, state]);
}

In this, side effects are dependent on the state or props, and will only change when either or both of them change.

Conclusion

useEffect hook is the hook that performs side-effects in functional components the same way lifecycle methods perform in class components, but they are better as they can update the effects every time either DOM changes or the state or prop changes depending upon the number of arguments we are using.

We don’t have to write the same piece every time we have run a lifecycle method as React manages every lifecycle method on its own and on time with the help of this hook.

Share your love

Leave a Reply