Summary: in this tutorial, you will explore the React useEffect()
hook, and learn how and when to use it properly.
Understanding React useEffect hook
In React, side effects include data fetching, manual DOM manipulation, or any other operations that impact outside of the component.
To perform side effects in function components, you use the useEffect
hook. To use the useEffect
hook, you first import it from the react library:
import { useEffect } from 'react';
Code language: JavaScript (javascript)
Then, you can use it in your component with the following syntax:
useEffect(setup, dependencies)
Code language: JavaScript (javascript)
The useEffect
hook is a function that takes two arguments:
setup
is the main function containing side effects, which you want to execute.dependencies
is an optional array of dependent values that determine when thesetup
function should run. TheuseEffect
hook will run thesetup
function based on theitems
specified in thedependencies
array.
The setup
function can optionally return a cleanup function:
return cleanup;
Code language: JavaScript (javascript)
React executes the cleanup
function before it unmounts the component or before the setup
re-runs (except the first time).
In the cleanup
function, you may include code for cleaning up resources such as clearing intervals or canceling a network request (AbortController
).
Typically, you’ll write the useEffect
hook as follows:
useEffect(() => {
// Side effect code here
return () => {
// Cleanup code here (optional)
};
}, [dependencies]);
Code language: JavaScript (javascript)
In this syntax, you define an arrow function for the setup
function:
() => {
// Side effect code here
return () => {
// Cleanup code here (optional)
};
}
Code language: JavaScript (javascript)
And include values in the dependencies
array:
[dependencies]
Code language: JavaScript (javascript)
Run an effect only once
To run an effect ( or a function) once when the component mounts, you use an empty array as the dependencies
array:
useEffect(() => {
// This code runs once
}, [])
Code language: JavaScript (javascript)
In practice, you use this pattern to run a function during the initial render of the component. For example, you can run a function that fetches data from an API only once when the component mounts.
The following UserList
component displays a list of users by calling the API endpoint https://jsonplaceholder.typicode.com/users
:
import React, { useEffect, useState } from 'react';
export default function UserList() {
const [users, setUsers] = useState([]);
const fetchUsers = async () => {
const url = 'https://jsonplaceholder.typicode.com/users';
const response = await fetch(url);
const data = await response.json();
setUsers(data);
};
useEffect(() => {
fetchUsers();
}, []);
return (
<div>
<h1>User List</h1>
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
</div>
);
}
Code language: JavaScript (javascript)
Run an effect whenever dependencies change
To run a function when certain values change, you can specify those values in the dependencies
array.
The following CounterTitle
component utilizes the useEffect()
hook to update the document title when the count
state variable changes:
import { useState, useEffect } from 'react';
const CounterTitle = () => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return (
<div>
<h1>Current count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default CounterTitle;
Code language: JavaScript (javascript)
Run an effect after every rerender
To run a function during the initial render and after every rerender, you pass only the setup
function to the useEffect()
function and skip the dependencies
array.
For example, you can log a message when the component renders and every time it re-renders by using the useEffect()
function:
import React, { useState, useEffect } from 'react';
const Counter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Component rendered or rerendered');
});
return (
<div>
<h1>Current count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
export default Counter;
Code language: JavaScript (javascript)
Run a cleanup function
The following WindowDimension
component listens for window resize events and updates the width and height state variables based on the window’s size:
import { useState, useEffect } from 'react';
function WindowDimension() {
const [width, setWidth] = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
useEffect(() => {
// Define the handler function that updates the state with the window's width
const handleResize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};
// Add the event listener for window resize
window.addEventListener('resize', handleResize);
// Cleanup function: Remove the event listener when the component unmounts
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return (
<div>
<p>
Current dimension: {width}x{height}px
</p>
</div>
);
}
export default WindowDimension;
Code language: JavaScript (javascript)
How it works.
First, define handleResize()
function to update the width and height state varibles based on the window’s innerWidth
and innerHeight
:
const handleResize = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
};
Code language: JavaScript (javascript)
Second, register an event listener for the resize event using the handleResize()
function:
window.addEventListener('resize', handleResize);
Code language: JavaScript (javascript)
Third, return a cleanup function from the useEffect
, which removes the resize event listener uisng window.removeEventListener
method:
return () => {
window.removeEventListener('resize', handleResize);
};
Code language: JavaScript (javascript)
This prevents the component to call the handleResize
function after it is removed from the DOM
, which may lead to memory leak and unwanted behavior.
Summary
- Use
useEffect(setup)
to run thesetup
function when the component renders and re-renders. - Use
useEffect(setup,[])
to run thesetup
function once during the initial render. - Use
useEffect(setup, [dependencies])
to run thesetup
function when the component renders and every time the items in thedependencies
array change.