useEffect Hook
Overview
The useEffect
Hook is a powerful tool in React that allows you to perform side effects in your function components. Side effects can include tasks such as data fetching, subscriptions, or manually changing the DOM. The useEffect
Hook replaces lifecycle methods like componentDidMount
, componentDidUpdate
, and componentWillUnmount
in class components.
Key Concepts
1. Basic Usage
import { useEffect } from "react";
useEffect(() => {
// Code to run on component mount
console.log("Component mounted");
return () => {
// Code to run on component unmount
console.log("Component unmounted");
};
}, []); // The empty array ensures this effect only runs once on mount and unmount
Effect Function: The first argument to
useEffect
is a function that contains the side-effect logic. This function is executed after every completed render by default.Cleanup Function: The function returned from the effect function is the cleanup function. It is invoked before the component unmounts or before the effect is re-executed on subsequent renders.
Dependency Array: The second argument is an array of dependencies. If this array is empty (
[]
), the effect only runs once when the component mounts and cleans up when the component unmounts.
2. Fetching Data with useEffect
useEffect
import { useEffect, useState } from "react";
function App() {
const [data, setData] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then(response => response.json())
.then(data => setData(data));
}, []); // Empty dependency array to run the effect only on mount
return (
<div>
{data.map(post => (
<div key={post.id}>{post.title}</div>
))}
</div>
);
}
Data Fetching: The effect runs once on component mount to fetch data from an API. The empty dependency array ensures the fetch operation is only triggered once.
Updating State: The data is stored in the component’s state using
useState
, and rendered in the component.
3. Listening to Window Resize Events
import { useEffect, useState } from "react";
function App() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
function handleResize() {
setWindowWidth(window.innerWidth);
}
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // No dependencies ensure that the resize listener is set up only once
return (
<div>
<h1>Window width: {windowWidth}</h1>
</div>
);
}
Event Listeners: The
useEffect
Hook is used to add and remove event listeners, ensuring that resources are cleaned up properly when the component unmounts.
4. Dependency Management
import { useEffect, useState } from "react";
function App() {
const [resourceType, setResourceType] = useState('posts');
const [items, setItems] = useState([]);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/${resourceType}`)
.then(response => response.json())
.then(json => setItems(json));
}, [resourceType]); // Effect re-runs when `resourceType` changes
return (
<div>
<button onClick={() => setResourceType('posts')}>Posts</button>
<button onClick={() => setResourceType('users')}>Users</button>
<button onClick={() => setResourceType('comments')}>Comments</button>
<h1>{resourceType}</h1>
<div>{JSON.stringify(items)}</div>
</div>
);
}
Dependencies: The effect listens for changes in the
resourceType
state variable. The effect re-executes wheneverresourceType
changes, fetching new data based on the current type.
5. Cleaning Up Effects
useEffect(() => {
const interval = setInterval(() => {
console.log('This will run every second');
}, 1000);
return () => clearInterval(interval); // Cleanup to prevent memory leaks
}, []);
Memory Leaks: Always clean up subscriptions, timers, or listeners to avoid memory leaks when components unmount or re-render.
Gotchas
Order of Hook Calls: Hooks must be called in the same order on every render. Don’t call hooks conditionally.
Avoiding Stale Closures: Be cautious of stale closures where the effect refers to outdated variables from a previous render. Consider including these variables in the dependency array.
Avoid Overusing Effects: Use
useEffect
wisely. Not every side effect needs to be placed inuseEffect
. If the side effect doesn’t involve the DOM or external data, it might not need an effect.
Conclusion
The useEffect
Hook is a cornerstone of functional React components, enabling them to handle side effects in a clean, declarative way. Properly understanding how and when to use useEffect
will make your components more efficient, responsive, and easier to maintain.
Additional Resources
Was this helpful?