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.