Introduction to useEffect() Hook In ReactJS – Part One

Introduction

In the previous article, we learned about useState hook along with its various examples and usage with the functional components. In this article, we will learn about useEffect() hooks and how to use them in React. 

useEffect() in React

The React useEffect hook allows adding side-effects in a functional component. Previously, in-class component, we saw that to perform side effects, we need to use component life cycle methods like componentDidMount(), componentDidUpdate() and componentWillMount().

In class component, when any update is needed via the lifecycle, we need to call it twice, but this is not the case when using Hooks. For example, to update the title of a document in the browser, we have the below code using class component.

import React, { Component } from 'react'      
class UseEffectDemo extends Component {     
    constructor(props) {      
        super(props)      
        this.state = {      
            title: 'React'      
        }      
        this.updateTitle = this.updateTitle.bind(this)      
    }      
    updateTitle(e) {      
        this.setState({      
            title: e.target.value      
        })      
        e.preventDefault();      
    }      
    componentDidMount() {      
        document.title = `New ${this.state.title}`      
    }      
    componentDidUpdate() {      
        document.title = `New ${this.state.title}`      
    }      
    render() {      
        return (      
            <div>      
                <input type="text" value={this.state.title} onChange={this.updateTitle}></input>      
            </div>      
        )      
    }      
}      
export default UseEffectDemo    

This will display output as below.

As we type further, the title is getting updated automatically.

Now, we will look at the same demo using useEffect() Hook. 

Let us create a function in UseEffectHook.js.

import React, { useState, useEffect } from 'react'      
function UseEffectFunction() {      
    const initialTitle = 'React'      
    const [title, setTitle] = useState(initialTitle);      
    useEffect(() => {      
        document.title = `New ${title}`      
    })      
    return (      
        <div>      
            <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />      
        </div>      
    )      
}      
export default UseEffectFunction    

This will display the same output as a class component.

Initially, it will display the value as React.

Later, as we type in the textbox, the same value will get updated in the title. So, the useEffect() hook will run on first, as well as, every renders to update the values as per your requirement.

One thing to remember while using useEffect() hook is that it should be defined within the component. This will help to access all properties and the state of the component without additional code. Now, we will run useEffect() on every render. It should run conditionally. 

useEffect() call conditionally

Now, let’s check how to not re-render unnecessarily in both, class as well as a functional component.

import React, { Component } from 'react'      
class UseEffectDemo extends Component {      
    constructor(props) {      
        super(props)      
        this.state = {      
            title: 'React'    
          }    
        this.updateTitle = this.updateTitle.bind(this)      
    }      
    updateTitle(e) {      
        this.setState({      
            title: e.target.value,      
            count: 0      
        })      
        e.preventDefault();      
    }      
    componentDidMount() {      
        document.title = `New ${this.state.title}`      
    }      
    componentDidUpdate(prevProps, prevState) {      
        console.log("Render componentDidUpdate")      
        document.title = `New ${this.state.title}`      
    }      
    render() {      
        return (      
            <div>      
                <label>Button Clicked {this.state.count}</label>      
                <input type="text" value={this.state.title} onChange={this.updateTitle}></input>      
                <button onClick={() => this.setState({ count: this.state.count + 1 })}>Click Me</button>      
            </div>      
        )      
    }      
}      
export default UseEffectDemo   

In the output, when we write in the textbox, the render method is called. Now, on click of the button, it is again rendering, which is not required.

So, in the console, we can see that render is called multiple times.

Now, we will restrict the assignment of new value every time.

import React, { Component } from 'react'      
class UseEffectDemo extends Component {   
    constructor(props) {      
        super(props)      
        this.state = {      
            title: 'React'      
        }      
        this.updateTitle = this.updateTitle.bind(this)      
    }      
    updateTitle(e) {      
        this.setState({      
            title: e.target.value,      
            count: 0      
        })      
        e.preventDefault();      
    }      
    componentDidMount() {      
        document.title = `New ${this.state.title}`      
    }      
    componentDidUpdate(prevProps, prevState) {      
        if (prevState.title !== this.state.title) {      
            console.log("Render componentDidUpdate")    
            document.title = `New ${this.state.title}`    
        }      
    }    
      render() {    
        return (      
            <div>      
                <label>Button Clicked {this.state.count}</label>      
                <input type="text" value={this.state.title} onChange={this.updateTitle}></input>      
                <button onClick={() => this.setState({ count: this.state.count + 1 })}>Click Me</button>      
            </div>      
        )      
    }      
}      
export default UseEffectDemo  

The output will be as below.

Now, we will look at the same code for Functional component.

import React, { useState, useEffect } from 'react'      
function UseEffectFunction() {      
    const initialTitle = 'React'      
    const [title, setTitle] = useState(initialTitle);      
    const [count, setCount] = useState(0)      
    useEffect(() => {      
        console.log("useEffect rendered")      
        document.title = `New ${title}`      
    })      
    return (      
        <div>      
            <label>Button clicked {count}</label>      
            <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />      
            <button onClick={() => setCount(count + 1)}>Click Me</button>    
        </div>      
    )      
}      
export default UseEffectFunction 

The output will be as below.

So, after clicking on the button, useEffect() is called every time.

To prevent it from happening, we have the functionality within useEffect() function. 

We can pass a variable within it, as shown in the code below.

import React, { useState, useEffect } from 'react'      
function UseEffectFunction() {      
    const initialTitle = 'React'      
    const [title, setTitle] = useState(initialTitle);      
    const [count, setCount] = useState(0)      
    useEffect(() => {      
        console.log("useEffect rendered")      
        document.title = `New ${title}`      
    }, [title])      
    return (      
        <div>      
            <label>Button clicked {count}</label>      
            <input type="text" value={title} onChange={(e) => setTitle(e.target.value)} />      
            <button onClick={() => setCount(count + 1)}>Click Me</button>    
        </div>      
    )      
}      
export default UseEffectFunction  

The output will be displayed as below.

Summary

In this article, we have learned the concept of useEffect(), how it is used or defined, and how it can be implemented to call conditionally. 

In the next article, we are going to learn about how to use the useEffect() hook to call only once is some scenarios and use it with cleanup which will prevent a memory leak.

Any question or feedback or suggestion, please do comment and let me know.

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s