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