
Understanding useEffect in React: A Complete Beginner's Guide
React provides several built-in Hooks that make it easier to manage state and side effects in functional components. One of the most commonly used Hooks is useEffect.
In this article, we'll learn what useEffect is, why it's needed, and how to use it effectively with practical examples.
What is useEffect?
useEffect is a React Hook that allows you to perform side effects in functional components.
A side effect is any operation that interacts with something outside the component, such as:
- Fetching data from an API
- Updating the document title
- Setting up event listeners
- Using timers (
setTimeout,setInterval) - Accessing browser storage (
localStorage)
Syntax
import { useEffect } from "react";
useEffect(() => {
// Side effect code
}, []);
The first argument is a function containing the side effect.
The second argument is the dependency array, which controls when the effect runs.
1. Running useEffect Only Once
If you pass an empty dependency array, the effect runs only once after the component mounts.
import { useEffect } from "react";
function App() {
useEffect(() => {
console.log("Component Mounted");
}, []);
return <h1>Hello React</h1>;
}
Output
Component Mounted
This is similar to componentDidMount() in class components.
2. Running useEffect on Every Render
If you don't provide a dependency array, the effect runs after every render.
useEffect(() => {
console.log("Component Rendered");
});
Whenever the component re-renders, this effect will execute.
Be careful because unnecessary executions can affect performance.
3. Running useEffect When a Value Changes
You can specify dependencies inside the array.
import { useState, useEffect } from "react";
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Count changed:", count);
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
Count: {count}
</button>
);
}
The effect runs only when count changes.
4. Fetching Data with useEffect
One of the most common use cases is fetching data from an API.
import { useState, useEffect } from "react";
function Users() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((data) => setUsers(data));
}, []);
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
The API request is made only once when the component loads.
5. Cleanup Function in useEffect
Sometimes you need to clean up resources when a component is removed.
Examples include:
- Removing event listeners
- Clearing intervals
- Cancelling subscriptions
useEffect(() => {
const interval = setInterval(() => {
console.log("Running...");
}, 1000);
return () => {
clearInterval(interval);
};
}, []);
The function returned from useEffect is called the cleanup function.
It runs before the component unmounts.
6. Multiple useEffect Hooks
You can use multiple effects inside the same component.
useEffect(() => {
console.log("Component Mounted");
}, []);
useEffect(() => {
console.log("Count Updated");
}, [count]);
This keeps your code organized by separating different responsibilities.
Common Mistakes
Missing Dependency
useEffect(() => {
console.log(count);
}, []);
If count changes later, the effect won't run because it's not included in the dependency array.
Correct version:
useEffect(() => {
console.log(count);
}, [count]);
Infinite Loop
useEffect(() => {
setCount(count + 1);
}, [count]);
This continuously updates state and causes an infinite re-render loop.
Always be careful when updating state inside an effect.
When Should You Use useEffect?
Use useEffect when you need to:
- Fetch data from APIs
- Update the browser title
- Manage subscriptions
- Work with timers
- Store or retrieve data from localStorage
- Interact with external systems
Do not use useEffect for calculations that can be done directly during rendering.
Conclusion
The useEffect Hook is one of the most powerful tools in React. It helps functional components perform side effects such as data fetching, event handling, and cleanup operations.
Remember these three common patterns:
// Run once
useEffect(() => {}, []);
// Run on every render
useEffect(() => {});
// Run when dependency changes
useEffect(() => {}, [dependency]);
By understanding these patterns and using dependency arrays correctly, you can build more efficient and maintainable React applications.

