useEffect Hook In ReactJS - Part Two

Introduction

 
In the previous article, we have learned about what is useEffect() hook is and how it is used in ReactJs. Now, in this article continuing the previous article, we will learn about calling useEffect only once and using with along with cleanup
 

useEffect() Hook to call once

 
In React, we know that useEffect() is called on every render, so every time any changes occur in render() function, useEffect() is called, as previously we reviewed how to call useEffect() only when changes on that event happened. Now in some cases like the binding event to windows, we need to call useEffect() hook only once so, to do that, we will pass an empty array to useEffect().
 
Let’s look at the demo by both ways,
 
First, class component to display mouse position,
  1. import React, { Component } from 'react'  
  2.   
  3. class MouseClass extends Component {  
  4.     constructor(props) {  
  5.         super(props)  
  6.       
  7.         this.state = {  
  8.              x:0,  
  9.              y:0  
  10.         }  
  11.     }  
  12.       
  13.     componentDidMount(){  
  14.         console.log("component Mounted")  
  15.         window.addEventListener('mousemove',this.logMousePosition)  
  16.     }  
  17.   
  18.     logMousePosition = e => {  
  19.         this.setState({  
  20.             x: e.clientX,  
  21.             y: e.clientY  
  22.         })  
  23.     }  
  24.   
  25.     render() {  
  26.         return (  
  27.             <div>  
  28.                 X Co-ordinate: {this.state.x}, y Co-ordinate: {this.state.y}  
  29.             </div>  
  30.         )  
  31.     }  
  32. }  
  33.   
  34. export default MouseClass   
This will display output as below,
 
On moving mouse, componentDidMount() is called only once when the component is mounted.
 
So, in the same way, to achieve the same functionality using hook we have useEffect() hook.
 
Create a functional component MouseHook.js
  1. import React,{useState,useEffect} from 'react'  
  2.   
  3. function MouseHook() {  
  4.     const [x,setX] = useState(0);  
  5.     const [y,setY] = useState(0);  
  6.   
  7.     const logMousePosition = e => {  
  8.         console.log("Mouse moved")  
  9.         setX(e.clientX)  
  10.         setY(e.clientY)  
  11.   
  12.     }  
  13.     useEffect(()=>{  
  14.         console.log("useEffect")  
  15.         window.addEventListener("mousemove",logMousePosition)  
  16.     })  
  17.   
  18.     return (  
  19.         <div>  
  20.             x Co-ordinate = {x}  
  21.             y Co-ordinate = {y}  
  22.         </div>  
  23.     )  
  24. }  
  25.   
  26. export default MouseHook  
This will output as below.
 
On moving cursor, x and y coordinates are getting changed.
 
 
Now observe console, every time useEffect is also getting called which is a binding event to Windows which is totally unnecessary so to prevent it from happening, we will pass an empty array as the second parameter to useEffect() hook,
  1. import React,{useState,useEffect} from 'react'  
  2.   
  3. function MouseHook() {  
  4.     const [x,setX] = useState(0);  
  5.     const [y,setY] = useState(0);  
  6.   
  7.     const logMousePosition = e => {  
  8.         console.log("Mouse moved")  
  9.         setX(e.clientX)  
  10.         setY(e.clientY)  
  11.   
  12.     }  
  13.     useEffect(()=>{  
  14.         console.log("useEffect")  
  15.         window.addEventListener("mousemove",logMousePosition)  
  16.     },[])  
  17.   
  18.     return (  
  19.         <div>  
  20.             x Co-ordinate = {x}  
  21.             y Co-ordinate = {y}  
  22.         </div>  
  23.     )  
  24. }  
  25.   
  26. export default MouseHook   
Now, in the output below, we can see that only logMousePosition method is getting called.
 
 
This way we can command useEffect() hook as per our requirements. Now moving ahead, we will see how useEffect handles unmounting to prevent a memory leak.
 

useEffect with cleanup

 
As we know when using class component, we have component life cycle functions componentDidUnmount() to unmount or clean up the code. In the same way useEffect() hook provides a way to perform clean up.
 
Let’s look at the demo, create a ToggleMouseHook.js,
  1. import React, { useState, useEffect } from 'react'  
  2. import MouseHook from './MouseHook'  
  3.   
  4. function ToggleMouseHook() {  
  5.   
  6.     const [display, setDisplay] = useState(true)  
  7.     return (  
  8.         <div>  
  9.             <button onClick={() => setDisplay(!display)}>Toggle</button>  
  10.             {display && <MouseHook/>}  
  11.         </div>  
  12.     )  
  13. }  
  14.   
  15. export default ToggleMouseHook   
The output will be displayed like below.
 
 
Now click on Toggle button,
 
 
As we noticed that there is a console error when clicking on the toggle button, it is due to the component being hidden but it is not unmounted so useEffect() hook will be used to unmount when the container not required. Let’s look at the demo,
  1. import React,{useState,useEffect} from 'react'  
  2.   
  3. function MouseHook() {  
  4.     const [x,setX] = useState(0);  
  5.     const [y,setY] = useState(0);  
  6.   
  7.     const logMousePosition = e => {  
  8.         console.log("Mouse moved")  
  9.         setX(e.clientX)  
  10.         setY(e.clientY)  
  11.   
  12.     }  
  13.     useEffect(()=>{  
  14.         console.log("useEffect")  
  15.         window.addEventListener("mousemove",logMousePosition)  
  16.   
  17.         return() => {  
  18.                 console.log('useEffect hook unmounted')  
  19.                 window.removeEventListener("mousemove",logMousePosition)  
  20.         }  
  21.     },[])  
  22.   
  23.     return (  
  24.         <div>  
  25.             x Co-ordinate = {x}  
  26.             y Co-ordinate = {y}  
  27.         </div>  
  28.     )  
  29. }  
  30.   
  31. export default MouseHook  
Now the output will be displayed as below,
 
 

Summary

 
In this article, we have learned about useEffect() hook calling only once and how to perform cleanup with useEffect() hooks in ReactJS.
 
You can download the source code attached to this article. In the next article, we will go in details of fetching data from API and sending it to using useEffect() hook.