In this article, we will learn how to run useEffect hook only once using functional components. 

In the last example, we saw how to conditionally run effects. In this article, let's see how to run an effect only once or with the knowledge of class components how to mimic componentDidMount with useEffect and functional components.

Class Component Example

First, let's quickly take a look at an example that makes use of class components 

import React, { Component } from 'react'

class ClassMouse extends Component {
constructor(props) {
super(props)

this.state = {
x: 0,
y: 0
}
}

logMousePosition = e => {
this.setState({ x: e.clientX, y: e.clientY })
}

componentDidMount() {
window.addEventListener('mousemove', this.logMousePosition)
}

componentWillUnmount() {
window.removeEventListener('mousemove', this.logMousePosition)
}

render() {
return (
<div>
X - {this.state.x} Y - {this.state.y}
</div>
)
}
}

export default ClassMouse

In the class component we have a constructor we have variables to store the X and y coordinate position of the mouse pointer.

In componentDidMount,  lets add an event listener that listen to the mouse move event and log the mouse position in the state variables we then rendered that position in the UI, if you take a look at the browser, I move the mouse around and you can see the coordinates changing.

What I want you guys to make note of here is that we set up the event listener only once and that is in componentDidMount

Functional Component Example

Let's implement the same with useEffect and functional components.

Let's create a new file called HookMouse.js and within the file, I'm going to create a functional component. 

import React from 'react'

function HookMouse() {
return (
<div>
</div>
)
}

export default HookMouse

I'm also going to import useState and useEffect from react, next I'm going to create two state variables for X&Y initialised to 0.

import React, { useState, useEffect } from 'react'

function HookMouse() {
const [x, setX] = useState(0)
const [y, setY] = useState(0)

return (
<div>
Hooks - X - {x} Y - {y}
</div>
)
}

export default HookMouse

In the JSX, I will render these state variables both the x coordinate and the y coordinate.

import React, { useState, useEffect } from 'react'

function HookMouse() {
const [x, setX] = useState(0)
const [y, setY] = useState(0)

return (
<div>
Hooks - X - {x} Y - {y}
</div>
)
}

export default HookMouse

Now, we need to add an event listener for the mouse event and this is where we use the effect hook, the useEffect accepts a function as an argument, within the function let's first add a log statement, console dot log use effect called and then we add the event listener, window dot add event listener which listen to the mouse move event and the event handler is log Mouse position.

Complete functional component example

import React, { useState, useEffect } from 'react'

function HookMouse() {
const [x, setX] = useState(0)
const [y, setY] = useState(0)

const logMousePosition = e => {
console.log('Mouse event')
setX(e.clientX)
setY(e.clientY)
}

useEffect(() => {
console.log('useFffect called')
window.addEventListener('mousemove', logMousePosition)

}, [])
return (
<div>
Hooks - X - {x} Y - {y}
</div>
)
}

export default HookMouse

Let's define log Mouse position which is going to accept event as its argument and within the body let's log Mouse event and then we are going to set the x coordinate, e dot client x and the y coordinate e dot clientY

if you now save the file and take a look at the browser in the console, you can see that we have use effect called from the initial render and now when i move the mouse around, you can see that the effect is called every time the component re-renders, this is not surprising though as it is exactly what we learned in the previous article.

The effect is called after every render unless you specify the dependency array.

For our example, we don't really want the effect to depend on anything, we want it to be called once on initial render only and the way we achieve that is by simply specifying an empty array as the second parameter to use effect.

We are basically telling react that, this particular effect does not depend on any props or state so there is just no reason for you to call this effect on re-renders and react replies so you want me to call this effect only on initial render and forget about it.

we have mimicked componentDidMount, if you now save the file and head back to the browser you can see that we have use effect called on initial render and when I move the mouse around, we only have the mouse event logs, the useEffect is not called on subsequent renders.

So the point to keep in mind from this example is that we can mimic component dig mount with use effect hook by simply passing in an empty array as the second parameter to useEffect now.