useEffect is the Swiss Army knife for working with all external operations in React components. A hook that moves everything related to the outside world out of JSX: data, subscriptions, timers, and DOM.
Dependency Array | Behavior | Class Component Analog |
---|---|---|
[] | Once after mounting | componentDidMount |
[dep] | When dependency changes | componentDidUpdate |
No array | After every render | ❌ Dangerous pattern |
Cleanup function | Cleanup before re-run/unmounting | componentWillUnmount |
When it’s really needed:
What it replaces from class components:
The useEffect hook is one of the most important hooks in React, allowing side effects to be performed in functional components. It combines the functionality of several lifecycle methods from class components.
useEffect is a hook that takes a function containing imperative code that can change the application state or interact with external APIs. This function runs after each component render (by default).
// Basic useEffect syntax
import { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
// Side effect
console.log('Component rendered');
// Cleanup function (optional)
return () => {
console.log('Component will be unmounted');
};
}, []); // Dependency array
return <div>My Component</div>;
}
An effect without a dependency array (when the second parameter is omitted) runs after every component render:
import { useEffect, useState } from 'react';
function Component() {
const [count, setCount] = useState(0);
// This effect will run after every render
useEffect(() => {
console.log('Effect executed');
document.title = `Counter: ${count}`;
});
// No dependency array!
return (
<div>
<p>Counter: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increase
</button>
</div>
);
}
// Tracking page title changes
function PageTitleUpdater({ title }) {
useEffect(() => {
// Update title on every render
document.title = title;
});
return <div>Page: {title}</div>;
}
// Logging all state changes
function Logger({ data }) {
useEffect(() => {
// Log every data change
console.log('Data changed:', data);
});
return <div>Logger: {JSON.stringify(data)}</div>;
}
The dependency array allows controlling when exactly the effect should run. It compares dependency values between renders and executes the effect only when they change.
[]
- effect runs once after the first render[dep1, dep2]
- effect runs when any dependency changesimport { useEffect, useState } from 'react';
function Component() {
const [count, setCount] = useState(0);
const [name, setName] = useState('');
// Runs once (after first render)
useEffect(() => {
console.log('Component mounted');
fetchData();
}, []); // Empty dependency array
// Runs when count changes
useEffect(() => {
console.log('Counter changed:', count);
}, [count]); // Array with one dependency
// Runs when count or name changes
useEffect(() => {
console.log('Counter or name changed');
}, [count, name]); // Array with two dependencies
return (
<div>
<p>Counter: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increase counter
</button>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Enter name"
/>
</div>
);
}
An empty dependency array []
means the effect doesn’t depend on any variables and will run only once:
import { useEffect } from 'react';
function Component() {
// Runs once after mounting
useEffect(() => {
console.log('This code will run only once');
// Event subscription
const handleResize = () => {
console.log('Window size changed');
};
window.addEventListener('resize', handleResize);
// Cleanup function
return () => {
window.removeEventListener('resize', handleResize);
console.log('Subscription cancelled');
};
}, []); // Empty dependency array
return <div>Component</div>;
}
An array with dependencies allows the effect to run only when specific values change:
import { useEffect, useState } from 'react';
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
// Runs when userId changes
useEffect(() => {
async function fetchUser() {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
setUser(userData);
}
if (userId) {
fetchUser();
}
}, [userId]); // Dependency on userId
if (!user) return <div>Loading...</div>;
return (
<div>
<h1>{user.name}</h1>
<p>{user.email}</p>
</div>
);
}
import { useEffect, useState } from 'react';
function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
// Load data once on mount
useEffect(() => {
async function fetchData() {
try {
const response = await fetch('/api/data');
const result = await response.json();
setData(result);
} catch (error) {
console.error('Loading error:', error);
} finally {
setLoading(false);
}
}
fetchData();
}, []); // Empty array - run once
if (loading) return <div>Loading...</div>;
if (!data) return <div>No data</div>;
return (
<ul>
{data.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
import { useEffect, useState } from 'react';
function WindowSize() {
const [size, setSize] = useState({
width: window.innerWidth,
height: window.innerHeight
});
// Subscribe to window resize event
useEffect(() => {
function handleResize() {
setSize({
width: window.innerWidth,
height: window.innerHeight
});
}
window.addEventListener('resize', handleResize);
// Clean up subscription on unmount
return () => {
window.removeEventListener('resize', handleResize);
};
}, []); // Run once
return (
<div>
<p>Width: {size.width}px</p>
<p>Height: {size.height}px</p>
</div>
);
}
import { useEffect, useState } from 'react';
function Timer() {
const [seconds, setSeconds] = useState(0);
// Start timer
useEffect(() => {
const interval = setInterval(() => {
setSeconds(prev => prev + 1);
}, 1000);
// Clean up interval
return () => {
clearInterval(interval);
};
}, []); // Run once
return (
<div>
<p>Seconds passed: {seconds}</p>
</div>
);
}
useEffect is a powerful tool for working with side effects in React:
✅ When to use:
Key points:
[]
means one-time execution[dep1, dep2]
runs effect when they changeUnderstanding how useEffect works allows efficient management of side effects and component lifecycle in React applications.
Want more articles for interview preparation? Subscribe to EasyAdvice, bookmark the site, and improve every day 💪