React is a powerful JavaScript library for building user interfaces, and it provides several special tools called Hooks to manage behavior in components. One of the most important and widely used hooks is useEffect
.
What is useEffect
?
useEffect
is a React Hook that lets you run side effects in function components. Side effects include tasks like:
- Fetching data from an API
- Updating the DOM
- Setting up event listeners
- Working with timers like
setInterval
orsetTimeout
- Interacting with localStorage or cookies
In class components, we used lifecycle methods like componentDidMount
, componentDidUpdate
, and componentWillUnmount
. In function components, useEffect
combines all those lifecycle behaviors into a single hook.
Syntax of useEffect
import { useEffect } from 'react';
useEffect(() => {
// Code to run (side effect)
}, [dependencies]);
Parts of useEffect
:
- Callback Function: The function that runs after the component renders.
- Dependency Array: Controls when the effect runs. It’s optional.
Example 1: Run Once (on Mount)
useEffect(() => {
console.log("Component mounted");
}, []);
Explanation:
This effect runs only once, when the component mounts — similar to componentDidMount
. It doesn’t run again unless the component is removed and added again.
Example 2: Run on State Change
useEffect(() => {
console.log("The count changed!");
}, [count]);
Explanation:
This effect runs every time the count
value changes.
Example 3: No Dependency (Run After Every Render)
useEffect(() => {
console.log("Component re-rendered");
});
Explanation:
Without a dependency array, the effect runs after every render — including after props or state updates. Use this with caution to avoid performance issues.
Example 4: Cleanup (Unmount or Before Re-run)
useEffect(() => {
const timer = setInterval(() => {
console.log("Running timer");
}, 1000);
// Cleanup function
return () => {
clearInterval(timer);
console.log("Cleanup");
};
}, []);
Explanation:
The returned function runs when the component unmounts or before the effect re-runs. This is useful for removing timers, event listeners, etc.
Common Uses of useEffect
Task | How useEffect Helps |
---|---|
Fetch data from an API | Run fetch on mount and update state |
Listen to window resize | Add and clean up event listeners |
Update document title | React to state changes by updating the page title |
Auto-save form data | Save input to localStorage whenever it changes |
Best Practices
- Always use a dependency array to avoid unnecessary re-renders.
- Use cleanup to avoid memory leaks.
- Avoid using async directly in the
useEffect
function — define an async function inside it if needed.
Avoiding Common Mistakes
Correct:
useEffect(() => {
const fetchData = async () => {
const res = await fetch("https://api.example.com/data");
const data = await res.json();
console.log(data);
};
fetchData();
}, []);
Incorrect:
useEffect(async () => {
const res = await fetch("...");
}, []);
React does not support making the main useEffect
function async
, because it expects a cleanup function or nothing — not a Promise.
Summary
useEffect
is one of the most essential hooks in React. It allows you to:
- Perform side effects in function components
- Control when and how effects run using the dependency array
- Replace class-based lifecycle methods in modern React
By learning how to use useEffect
properly, you can build interactive and dynamic components efficiently.