Intro to React Hooks- Part 9

Michael Rosenberg
4 min readJun 11, 2021

The last part of this series showed an example of how to conditionally run effects using the useEffect Hook. As a refresher, in order to conditionally run an effect, you need to specify a second parameter to useEffect. That second parameter is the array of values that the effect depends on. And if the values don’t change between renders, then the effect is not run.

This post will go over another example with the Effect Hook, this time showing how to run an effect only once. Or, if thinking about a Class Component, how to mimic componentDidMount with useEffect and a Functional Component.

Class Component Example

Like always, we’ll first take a look at this example when using a class component.

// Class.jsimport 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)
}
render() {
return (
<div>
X - {this.state.x} Y - {this.state.y}
</div>
)
}
}
export default ClassMouse

In this class component, you can see that we have a constructor, as well as variables to store the x and y coordinate positions of the mouse pointer. In componentDidMount, we add an event listener, which listens for the mousemove event and logs the mouse position in the state variables. We then render that position in the UI.

If you take a look at this code in your browser, you’ll see that as you move your mouse around, the X and Y coordinates change accordingly. What to make note of is that an event listener was set up only once, in componentDidMount.

Now we will take a look at implementing the same example with the useEffect Hook and a functional component.

Functional Component with useEffect Example

Let’s take a look at the following code which I’ll explain below:

// Hook.jsimport 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('useEffect called')
window.addEventListener('mousemove', logMousePosition)
})
return (
<div>
Hooks X - {x} Y - {y}
</div>
)
}
export default HookMouse

So, this time around we have a functional component, with useState and useEffect imported. And we have two state variables, x and y, initialized to 0. Then, in the JSX, we render these state variables.

Next, we add an event listener for the mouse event, and this is where we use the Effect Hook. useEffect accepts a function as an argument, and within the function we add a log statement to show us that useEffect has been called. Then, we add an event listener similar to the class component example, listening for the mousemove event which will call logMousePosition.

For logMousePosition, it accepts an event as an argument. And within the body, we add another log statement along with setting the x and y coordinates.

If you take a look at this code in your browser, and open the console, you will see that ‘useEffect called’ has been logged from the initial render. Then, if you clear the console and move your mouse around, you’ll see that the effect is being called every time the component re-renders. This shouldn’t come as a surprise, as we covered this in the previous parts of this series- the effect is called after every render, unless you specific a dependency array.

For this example, we don’t want the effect to depend on anything. We only want it to be called once, on initial render only. The way we can achieve this is by simply specifying an empty array as the second parameter to useEffect.

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

Here, we’re basically telling React that this particular effect does not depend on any props or state. And so there’s no reason for this effect to be called on re-renders. React then only calls this effect on initial render, and just that one time. And just like that, we have copied the functionality in componentDidMount using the Effect Hook in a functional component.

If you make the above change and go back to your browser to test this out one last time, you’ll again see ‘useEffect called’ being logged to the console on initial render. But now, when you move the mouse around, only the ‘Mouse event’ logs are showing up in the console. useEffect is no longer being called on every re-render.

Summary

The main takeaway from this example is that we can mimic componentDidMount with the useEffect Hook by simply passing in an empty array as the second parameter to useEffect.

Thanks as always for reading, and see you next time!

--

--

Michael Rosenberg

Software Engineer/Full Stack Web Developer | Ruby, JavaScript, React, Redux