Learn how to use the React useEffect hook with examples. Master side effects, data fetching, and component lifecycle in React for beginners.
React is a powerful JavaScript library that simplifies the process of building dynamic, interactive user interfaces. One of the core features of React is the ability to handle side effects in functional components, and the useEffect hook plays a critical role in this.
The useEffect hook is a function that allows you to perform side effects in functional React components. Side effects are operations that don’t directly affect the rendering of the UI but are necessary for the application to function properly. These can include tasks like data fetching, subscribing to events, timers, and manually manipulating the DOM.
Before the introduction of hooks in React 16.8, side effects in React were handled in class components using lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount. With the useEffect hook, developers can now handle these side effects in functional components, making functional components more powerful.
The basic syntax of the useEffect hook looks like this:
useEffect(() => {
// Code to perform side effect here
}, [dependencies]);Here’s a simple example of how to use useEffect in a functional component:
import React, { useState, useEffect } from 'react';
function ExampleComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("useEffect has been triggered!");
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}In this example, every time the count state changes, the useEffect hook is triggered, and the document title is updated accordingly.
One of the most important aspects of the useEffect hook is the dependencies array. This array helps determine when the effect should run.
If you omit the second argument, useEffect will run after every render, regardless of whether any state or props have changed. This is similar to componentDidUpdate in class components.
Example:
useEffect(() => {
console.log("This runs after every render!");
});If you pass an empty array [] as the second argument, the effect will only run once when the component mounts, and it will not run again on subsequent renders. This is similar to componentDidMount in class components.
Example:
useEffect(() => {
console.log("This runs only once when the component mounts!");
}, []);When you pass specific state or props values in the dependencies array, the effect will only run when those values change. This allows you to optimize when the side effect should trigger.
Example:
useEffect(() => {
console.log("This runs when 'count' changes!");
}, [count]);One of the most common use cases for the useEffect hook is to fetch data from an API when the component mounts. Let’s walk through a simple example that fetches data from a public API.
Example:
import React, { useState, useEffect } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/posts')
.then((response) => response.json())
.then((jsonData) => {
setData(jsonData);
setLoading(false);
})
.catch((error) => console.error('Error fetching data:', error));
}, []); // Empty array means it only runs once on mount
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<h1>Fetched Data</h1>
<ul>
{data.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}In this example, useEffect is used to fetch data from an API when the component mounts. The empty dependencies array [] ensures that the data is fetched only once when the component is first rendered.
Another key feature of useEffect is that it can handle cleanup operations. You can return a cleanup function inside the effect, which will be executed when the component unmounts or when the effect is triggered again (if dependencies change).
For example, cleaning up a timer:
import React, { useState, useEffect } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const timer = setInterval(() => setSeconds((prev) => prev + 1), 1000);
// Cleanup function to clear the timer when the component unmounts
return () => clearInterval(timer);
}, []); // Empty array means it runs only once on mount
return <div>Time: {seconds} seconds</div>;
}In this example, useEffect starts a timer when the component mounts. The cleanup function clears the timer when the component unmounts, preventing memory leaks.
You can also use useEffect to add and remove event listeners. For example, if you need to listen for window resize events, useEffect makes it easy.
import React, { useState, useEffect } from 'react';
function WindowSize() {
const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', handleResize);
// Cleanup event listener
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // Runs only once when the component mounts
return (
<div>
<p>Width: {size.width}</p>
<p>Height: {size.height}</p>
</div>
);
}This example listens for resize events and updates the component state whenever the window size changes. The event listener is removed when the component unmounts, preventing potential memory leaks.
Sometimes, you may want to conditionally trigger side effects. You can use the dependencies array to control which states or props trigger the effect. You can also conditionally set dependencies within the useEffect callback.
import React, { useState, useEffect } from 'react';
function ConditionalEffect() {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const [message, setMessage] = useState('');
useEffect(() => {
if (isLoggedIn) {
setMessage('Welcome back!');
} else {
setMessage('Please log in');
}
}, [isLoggedIn]); // The effect runs when 'isLoggedIn' changes
return (
<div>
<p>{message}</p>
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>Toggle Login</button>
</div>
);
}In this example, the side effect (updating the message) only occurs when the isLoggedIn state changes.
The useEffect hook is one of the most important and versatile hooks in React. It allows you to perform side effects like data fetching, timers, subscriptions, and more, all while keeping your components clean and efficient. By understanding how useEffect works and how to properly manage dependencies, you can create better React applications.
To summarize:
By mastering useEffect, you will be able to write more maintainable, efficient, and reactive React applications.