How to Use useEffect in React JS: A Beginner-Friendly Guide
Updated on Jul 23, 2025 | 9 min read | 57.33K+ views
Share:
For working professionals
For fresh graduates
More
Updated on Jul 23, 2025 | 9 min read | 57.33K+ views
Share:
Table of Contents
Did you know? Over 52 lakh live websites in India are powered by React! Its widespread adoption makes it the go-to choice for tackling complex API integrations and efficient data management in modern web apps. |
useEffect is a React Hook that lets you run side effects in function components, such as fetching data, updating the document, or reacting to state or prop changes. It’s essential for handling logic that runs outside the normal render cycle.
Understanding useEffect is crucial to building responsive and maintainable React applications. It helps manage API calls, event listeners, and cleanup tasks in a clean, predictable way.
In this blog, you’ll learn how useEffect in React JS works through clear, practical examples that prepare you for real-world React development.
The useEffect in React JS is the most commonly used hook for building React applications. You use useEffect in React to handle side effects, such as fetching data or updating the DOM. By default, it runs after every render. But you can control when it runs by using a dependency array.
Here’s the syntax you’ll use to get started.
useEffect(() => {
// Your side-effect logic here
}, [dependencies]);
If you’re aiming to boost your React skills or grow in your developer journey, these top courses can help you move forward with confidence.
Now that you understand what useEffect in React JS does, let’s explore some of the most common ways you’ll use it in real projects.
Software Development Courses to upskill
Explore Software Development Courses for Career Progression
You’ll often use useEffect to handle tasks that need to run outside the normal rendering flow. These tasks, known as side effects, are everyday in real-world applications. Whether you're working with data, browser APIs, or external services, useEffect helps you manage those actions cleanly and efficiently. Here are some of the most common scenarios where you’ll use it:
Also read: Top 8 React JS Free Courses with Certificate Options [2025]
Let’s explore why useEffect in React JS is such a crucial component for building functional components effectively.
React used to rely on class-based lifecycle methods like componentDidMount and componentDidUpdate. With Hooks, especially useEffect, you can achieve the same results in function components, with less boilerplate and more clarity.
You should use useEffect because:
Explore the language behind React. Before building dynamic forms, get confident with JavaScript, the core of all modern web apps. Enroll in the upGrad’s JavaScript Basics from Scratch course and create interactive websites from the ground up.
Also Read: A Complete Guide to the React Component Lifecycle: Key Concepts, Methods, and Best Practices
Now that you understand what useEffect does, let’s break down how the dependency array affects when and how it runs.
Subscribe to upGrad's Newsletter
Join thousands of learners who receive useful tips
When using useEffect in React JS, the dependency array helps you control when the effect runs. It’s a powerful feature that makes your component more predictable and efficient. Here’s how it works in different scenarios:
If you pass an empty array as the second argument to useEffect, the effect will run only once, after the component mounts, similar to componentDidMount in class components.
Sample Code:
useEffect(() => {
console.log("Component mounted");
}, []);
Use this when you want the effect to run only once, such as fetching data on initial load.
If you don’t provide any array, useEffect will run after every render, no matter what changes.
Sample Code:
useEffect(() => {
console.log("Effect ran after render");
});
This is useful for cases where you need to react to any change, but be cautious, as it can lead to unnecessary executions.
By including specific variables inside the array, you can make useEffect run only when those values change. This is the most common and recommended pattern. It helps you avoid redundant runs and keeps performance optimized.
Sample Code:
useEffect(() => {
console.log("Effect ran because count changed");
}, [count]);
Using the dependency array in useEffect in React JS is key to writing clean, efficient components that behave as expected during state or prop changes.
Also Read: React useCallback Hook: Why, When & How to Use It?
To see how useEffect in React JS works practically, let’s walk through some practical examples and understand how it fits into the component lifecycle.
When working with React functional components, knowing how to implement useEffect effectively can save you time and prevent bugs. From mimicking lifecycle methods to fetching data from APIs, useEffect helps manage side effects cleanly and predictably.
Let’s explore real examples where you can use useEffect in React JS, along with code, output, and clear explanations.
Example 1: Fetching Data from an API
import { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(data => setUsers(data));
}, []);
return (
<ul>
{users.map(user => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
}
Code Explanation: In this example, useEffect runs once when the component mounts to fetch user data. After fetching, the response is stored in the user's state and displayed in a list.
Output (UI):
Example 2: Responding to State Changes
import { useState, useEffect } from 'react';
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);
}
Code Explanation: This useEffect updates the document title every time the count state changes. The effect only applies when the count updates, as it's listed in the dependency array.
Output :
Also Read: React JS Architecture Explained: Explore Step-by-Step Implementation and Key Tools
While useEffect in React JS is powerful, it’s easy to misuse. Let’s look at some common mistakes developers make and how you can avoid them.
While useEffect is incredibly powerful, it can also lead to bugs or performance issues if not used correctly. When working with useEffect in React JS, it's essential to avoid common pitfalls and follow reliable patterns to keep your components efficient and predictable.
If you don’t pass a dependency array, your effect will run after every render, which may cause unwanted side effects, slow your application, and hang your system.
Wrong:
useEffect(() => {
console.log("Runs on every render");
});
Fix:
Add a proper dependency array to control when the effect should run. This helps you avoid unnecessary executions and ensures the impact only runs when specific values, such as props or state, actually change. It keeps your component efficient, prevents performance issues, and avoids bugs caused by stale data or repeated side effects.
Sample Code:
useEffect(() => {
console.log("Runs only once on mount");
}, []);
When you use state or props inside a useEffect, you need to include them in the dependency array. If you don’t, React won’t know to re-run the effect when those values change. This can lead to outdated (stale) data being used, causing bugs or unexpected behavior in your app.
Wrong:
useEffect(() => {
if (query !== '') {
fetchData(query); // query is used but not listed
}
}, []);
Fix:
Always include all variables that are used inside the effect by separating them with commas if there are more than 1.
Sample Code:
useEffect(() => {
if (query !== '') {
fetchData(query);
}
}, [query]);
When you use useEffect to set up things like event listeners, intervals, timeouts, or subscriptions (such as WebSocket connections), cleanup is crucial. You should remove or cancel these side effects when the component unmounts or before the effect runs again. Skipping cleanup can cause memory leaks, duplicate handlers, or unexpected behavior in your app.
Wrong:
useEffect(() => {
window.addEventListener('resize', handleResize);
}, []);
Fix:
Return a cleanup function inside useEffect.
Sample Code:
useEffect(() => {
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
Also Read: React.js vs Node.js: The Battle of JavaScript Frameworks
Let’s see how upGrad can support your journey with useEffect in React JS and front-end development.
useEffect in React JS helps your components interact with the UI, whether it’s fetching data, syncing with APIs, updating the DOM, or more. From managing dependencies to handling cleanup logic, understanding this hook is key to writing clean, efficient, and responsive React applications.
But understanding how it works isn’t enough. You need to apply it in real scenarios, build components, debug behaviors, and write side-effect logic that scales.
That’s where upGrad can help. Whether you're starting in React or aiming to level up your front-end skills, upGrad’s software development courses guide you through hooks, component lifecycles, and many more through expert guidance and live sessions.
Here are some additional courses to strengthen your frontend development:
Not sure how useEffect in React JS is applied in real-world projects? Connect with upGrad’s expert counselors or drop by your nearest upGrad offline center to discover a personalized learning path aligned with your goals.
Boost your career with our popular Software Engineering courses, offering hands-on training and expert guidance to turn you into a skilled software developer.
Master in-demand Software Development skills like coding, system design, DevOps, and agile methodologies to excel in today’s competitive tech industry.
Stay informed with our widely-read Software Development articles, covering everything from coding techniques to the latest advancements in software engineering.
Reference:
https://trends.builtwith.com/javascript/React
useEffect runs after the component has been painted to the screen, while useLayoutEffect runs synchronously right after the DOM mutations but before the browser repaints. This makes a helpful uselayouteffect for tasks like measuring DOM elements or synchronizing scroll positions—anything where visual layout matters. However, in most cases, useEffect is the right choice since it’s non-blocking and more beneficial for performance. Only use useLayoutEffect when you specifically need to measure or manipulate the DOM before it’s visually updated.
You can avoid unnecessary re-renders by properly using the dependency array in useEffect. Only include variables that truly impact the side effect. Also, memoize callbacks using useCallback and memoize values with useMemo where applicable. Avoid creating new object or function references in your component unless they’re needed, as those trigger a new render or effect. And remember, React.memo can help you memoize whole components, preventing them from re-rendering unless props change.
Use useRef when you want to persist a mutable value across renders without causing re-renders. This is especially useful for storing previous values, timers, or DOM nodes. Inside useEffect, useRef can be used to avoid stale closures by constantly referencing the latest value. Unlike useState, updating a ref doesn’t trigger a component update, which makes it more efficient for tracking values that don’t affect rendering.
React’s useEffect can replicate all these lifecycle methods depending on how you configure the dependency array:
This pattern gives you complete control over when and how your effects run, making function components just as powerful as class-based ones.
When making async calls inside useEffect, always define the async function inside the effect, not directly in the argument. To prevent race conditions, you can use an isMounted flag or an AbortController to cancel the request if the component unmounts before the fetch completes. This prevents setting state on unmounted components, which can lead to memory leaks and console warnings.
This typically happens when you include non-primitive values like objects, arrays, or functions directly in the dependency array. React compares dependencies using reference equality, so even if the content is the same, a new reference will be treated as a change. To fix this, you can memoize those dependencies using useMemo or useCallback, or restructure your logic to avoid including them if unnecessary.
Start by ensuring each useEffect hook is scoped to a specific task—don't overload one hook with multiple concerns. Use dependency arrays wisely to avoid over-triggering. Where possible, batch state updates or debounce expensive operations like API calls or calculations. Also, consider lazy-loading components, code splitting, and using React’s built-in Suspense and React.memo for optimization.
Yes, you can use multiple useEffect hooks in one component to separate concerns. Each effect should handle a single responsibility, such as data fetching, setting up subscriptions, or syncing state with local storage. Keeping them separate improves readability and maintainability. There’s no strict order of execution, but they will run in the order they’re defined in the component.
You can integrate utilities like lodash.debounce or lodash.throttle inside useEffect to delay state updates. For example, when listening to user input or scroll events, wrap the handler in a debounce function and ensure cleanup is done correctly by cancelling the debounced function in the effect’s return statement. This prevents unnecessary state updates, improving performance in real-time apps.
To sync storage with React state, you can:
Remember to handle parsing errors when reading JSON data and use try-catch blocks to prevent crashes. This pattern ensures persistent state across page reloads and browser sessions.
When integrating third-party libraries, initialize them inside useEffect after the component mounts. For example, if you're using Chart.js or Leaflet, create the chart or map inside the effect. Store any instance references in a useRef and return a cleanup function to destroy or unmount the instance to avoid memory leaks. Be cautious with dependencies if the library instance depends on props or state; make sure those are included in the dependency array.
900 articles published
Pavan Vadapalli is the Director of Engineering , bringing over 18 years of experience in software engineering, technology leadership, and startup innovation. Holding a B.Tech and an MBA from the India...
Get Free Consultation
By submitting, I accept the T&C and
Privacy Policy
India’s #1 Tech University
Executive PG Certification in AI-Powered Full Stack Development
77%
seats filled
Top Resources