Home

Published

- 5 min read

How To Use the useEffect Hook in React

img of How To Use the useEffect Hook in React

Introduction

If you are starting to get into React, you might have come across the useEffect hook.

It’s one of the most commonly used hooks in React after useState.

But to understand the useEffect hook better, we need to understand some associated terms like side effects.

So let’s dive in.

What are side-effects?

‘Side effect’ is a concept borrowed by React from functional programming.

A side effect is when a function depends on something other than its inputs to perform its operations.

If a function interacts with the outside world, then it’s said to have a side effect.

The outside world could include:

  • Interacting with browser APIs
  • Logging
  • Throwing errors
  • Making network calls

E.g.:

   function add(num1, num2) {
	return num1 + num2
}

The add function interacts with just its inputs and performs a computation.

Contrast the above add function with this function:

   function printAdd(num) {
	console.log('Add: ' + num1 + num2)
}

The printAdd function interacts with a browser API(console.log) that isn’t an input.

The printAdd function thus contains a side effect.

How to use the useEffect hook?

The useEffect hook in React is mainly used to host side-effects.

Side effects may include subscriptions, logging, making network requests or interacting with browser APIs.

E.g: Let’s say we wish to make an HTTP request to fetch a list of users and display the list in our React component.

   import { useEffect, useState } from 'react'
import './styles.css'
export default function App() {
	const [users, setUsers] = useState()
	useEffect(() => {
		fetch('https://mocki.io/v1/d4867d8b-b5d5-4a48-a4ab-79131b5809b8')
			.then((response) => response.json())
			.then((data) => {
				setUsers(data)
			})
	})
	return (
		<div className='App'>
			<h2>Users</h2>
			<ul>{users && users.map((user) => <li key={user.name}>{user.name}</li>)}</ul>
		</div>
	)
}

Now let’s see what’s going on here.

The ‘useEffect’ hook takes a function as an argument.

   useEffect(() => {
	// Perform side effects
})

React runs the function passed to the useEffect hook when your component is mounted, i.e., after React has added it to the DOM and the browser has displayed it on the screen.

In the function passed to the ‘useEffect’ hook, you could perform any side effects such as making network requests, adding timers or logs, accessing browser storage, adding subscriptions etc.

As side effects are typically time-taking operations it’s better to add them in the ‘useEffect’ hook as it won’t block the browser from doing its work of displaying the component on screen.

Right now, the function passed to ‘useEffect’ by default runs for every render cycle.

If you don’t want that to happen, as it could impact your application’s performance, you could pass an optional second parameter to the ‘useEffect’ hook, i.e., a dependency array.

The dependency array signals React to run the function passed to ‘useEffect’ only on certain occasions.

Let’s see how to add a dependency array to the same ‘useEffect’ hook as in the above code snippet.

   useEffect(() => {
	fetch('https://mocki.io/v1/d4867d8b-b5d5-4a48-a4ab-79131b5809b8')
		.then((response) => response.json())
		.then((data) => {
			setUsers(data)
		})
}, [])

Passing an empty dependency array to the ‘useEffect’ hook tells React that we want to run the function passed to it only once when the component has mounted.

But what if we want to run that function more than once but not for every render cycle?

Then we could pass variables in the dependency array.

If the values of the dependencies change, the function passed to useEffect will run again.

E.g.: Let’s say we have a counter that updates on the click of a button.

   import './styles.css'
import { useState } from 'react'
export default function App() {
	const [count, setCount] = useState(0)
	const updateCountHandler = () => {
		setCount(count + 1)
	}
	return (
		<div className='container'>
			<button onClick={updateCountHandler}>Click</button>
			<p>No. of clicks: {count}</p>
		</div>
	)
}

If we wish to log the value of the count variable (which would be a side effect since console.log is a browser API) we would need to use the useEffect hook.

Since we would want the ‘useEffect’ hook to run every time the value of ‘count’ changes, we would need to add the ‘count’ variable to the dependency array.

Adding ‘count’ to the dependency array ensures that the useEffect hook runs once when the component is mounted and whenever the value of ‘count’ changes.

   import './styles.css'
import { useState, useEffect } from 'react'
export default function App() {
	const [count, setCount] = useState(0)
	const updateCountHandler = () => {
		setCount(count + 1)
	}

	useEffect(() => {
		console.log('Count value: ' + count)
	}, [count])

	return (
		<div className='container'>
			<button onClick={updateCountHandler}>Click</button>
			<p>No. of clicks: {count}</p>
		</div>
	)
}

useEffect for cleanup

The useEffect hook is not only used for setting up side effects but also for cleaning them up.

An example of a cleanup would be unsubscribing from a subscription.

The syntax for performing cleanup activities in useEffect hook looks something like this:

   useEffect(() => {
	return () => {
		// Perform cleanup
	}
})

The order of execution for useEffect hook is:

  • Run the cleanup function returned by the useEffect hook from the previous render cycle.
  • Run the function passed to useEffect for the current render cycle.

So every time the useEffect hook runs, it will check if it has a cleanup function for that render cycle.

If so, it will run the cleanup function first, and then the function passed to the useEffect hook.

Takeaway

useEffect is one of React’s most frequently used hooks, hence an important one.

I hope you now have gained a good understanding of the basics of useEffect hook and how it works.

If you wish to dive deeper into it, I recommend checking out the references.

Till then, Happy Coding!

References