ReactJS | useEffect Hook

The motivation behind the introduction of useEffect Hook is to eliminate the side-effects of using class-based components. For example, tasks like updating the DOM, fetching data from API end-points, setting up subscriptions or timers, etc can be lead to unwarranted side-effects. Since the render method is to quick to produce a side-effect one needs to use life cycle methods to observe the side effects. For example, consider updating the document title for a simple counter component to the current value. On initial render, we set the current clicked value to 0 clicks. So, this section is coded into the componentDidMount() method which is executed only once in the component life cycle. Then we create a button to increment the count state value by one on every click. As the count value state changes, we also need to update the document title again and for that, we need to write the same piece of code in componentDidUpdate(). The componentDidupdate() method is perfect for updating the counter value at any time the state changes but the repetition of code is one of the side-effects.

filter_none

edit
close

play_arrow

link
brightness_4
code

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

chevron_right


Let us consider another side-effect by setting up a timer. On the componentDidMount() method, we set a timer to log a string “hello” every 5 seconds. We can clear this timer when the component is being removed from the DOM. And we do that in componentWillUnmount() life-cycle method. So the code for the timer looks like below:

filter_none

edit
close

play_arrow

link
brightness_4
code

componentDidMount(){
    this.interval = setInterval(this.tick, 1000)
}
  
componentWillUnmount(){
    clearInterval(this.interval)
}

chevron_right


Both the counter and timer when merged to form a single component looks like below:

filter_none

edit
close

play_arrow

link
brightness_4
code

componentDidMount(){
    document.title = `you clicked ${this.state.count} times`;
    this.interval = setInterval(this.tick, 1000)
  
}
  
componentDidUpdate(){
    document.title = `you clicked ${this.state.count} times`;
    clearInterval(this.interval)
}

chevron_right


As you observe the code above, we tend to notice that to update the document title we write the same code twice, once in componentDidmount() and once in componentDidUpdate(). The second thing to observe how the code is split into the component. The code related to the timer, setInterval, and clearInterval which are related are put into different code blocks (i.e. different life-cycle methods). The code to update the DOM and code for setting up the timer which is completely unrelated are put in the same life-cycle method (i.e. in componentDidMount()). It will be much better if there is an option to not repeat code at the same time group together related codes in the same block. This is where the useEffect Hook comes in the picture.
The Efect Hook lets you perform side effects in functional components. It is a close replacement for componentDidMount(), componentDidUpdate() and componentWillUnmount() method.

useEffect after render: We know that, the useEffect() is used for causing side effects in functional components and it is also capable for handling componentDidMount(), componentDidUpdate() and componentWillUnmount() life-cycle methods of class based components into functional component. Let’s look at an example on how to use the useEffect hook as a feature that can mimic the above mentioned life-cycle methods but in functional components.
For better understanding lets look how the code looks like in a class component below and we are going to name it “ClassComponentOne”



Filename: src/components/ClassCounterOne.js

filter_none

edit
close

play_arrow

link
brightness_4
code

import React, { Component } from 'react'
  
class ClassCounterOne extends Component {
    constructor(props){
        super(props)
        this.state = {
            count: 0
        }
    }
  
componentDidMount(){
    document.title = `Clicked ${this.state.count} times`
}
  
componentDidUpdate(prevProps, prevState){
    document.title = `Clicked ${this.state.count} times`
}
  
render() {
    return (
        <div>
            <button onClick = {() => this.setState(
                  { count: this.state.count + 1})}>
                Click {this.state.count} times
            </button>
        </div>
    )
}
  
export default ClassCounterOne

chevron_right


Now, we include the component in App.js. The code will look like below for App.js

Filename: src/App.js

filter_none

edit
close

play_arrow

link
brightness_4
code

import React from 'react'
import './App.css'
import ClassCounterOne from './components/classCounterOne'
  
function App(){
    return(
        <div className='App'>
        <ClassCounterOne />
        </div>
    )
}
  
export default App

chevron_right


Now if we look at the browser we can observe that initially the document title is “Clicked 0 times”.
initial state

And if we click on the button the count value increments by 1 on each click and updates the title as well.

Now let’s try to replace the functionality with a functional component. For the same purpose create a new file and name it (say, HookCounterOne.js)
The functional component will look like the code below:

Filename: src/components/HookCounterOne.js

filter_none

edit
close

play_arrow

link
brightness_4
code

import React, { useState, useEffect } from 'react'
  
function HookCounterOne() {
    const [count, setCount] = useState(0)
  
    useEffect(() => {
        document.title = `You clicked ${count} times`
  
    return (
        <div>
            <button onClick = {() => setCount(count + 1)}>
                  Click {count} times </button>
        </div>
    )
}
export default HookCounterOne

chevron_right


Now we need to import the above component in our App.js file. After the inclusion of the HookCounterOne component, the code looks like below:

Filename: src/App.js

filter_none

edit
close

play_arrow

link
brightness_4
code

import React from 'react'
import './App.css'
import ClassCounterOne from './components/classCounterOne'
  
function App(){
    return(
        <div className='App'>
        <HooKCounterOne />
        </div>
    )
}
  
export default App

chevron_right


Now if we look into the browser we can see the initial state as below. Initially the document title reads “You clicked 0 times”.

And when you click on the button, the count value increments and the document title is updated. As we can observe the behavior is as expected.

When we specify useEffect we are basically requesting react to execute the function that we pass in the useEffect function as an argument, everytime the component renders. The second thing to make note of is that useeffect is used inside the component as buy doing this we can easily access the components state and props without having to write any additional code.

react-js-img




My Personal Notes arrow_drop_up

Developer with a dream

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.


Article Tags :

Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.