Part 16: Mastering useEffect: Lifecycles, Dependencies & Cleanup
The useEffect hook lets you synchronize your component with external systems: fetching network data, reading/writing to browser APIs, setting timers, and subscribing to external event streams.
1. The Anatomy of useEffect
import { useEffect } from 'react';
useEffect(() => {
// 1. Setup / Effect Code
console.log('Effect executed');
return () => {
// 2. Optional Cleanup Function
console.log('Cleanup executed');
};
}, [/* 3. Dependency Array */]);
2. Understanding the Dependency Array
The second argument controls when the effect executes:
Case 1: No Dependency Array
Runs on every single render (mount + every state/prop update):
useEffect(() => {
console.log('Component rendered or updated');
});
Case 2: Empty Dependency Array ([])
Runs once on initial mount, cleanup runs on unmount:
useEffect(() => {
console.log('Component mounted to DOM');
return () => console.log('Component unmounted');
}, []);
Case 3: Specific Dependencies ([userId, filter])
Runs on mount, and re-runs whenever any dependency changes value:
useEffect(() => {
fetchUserData(userId);
}, [userId]);
3. The Cleanup Function
Whenever your effect establishes a continuous resource (subscription, timer, event listener), you must return a cleanup function to prevent memory leaks:
import { useState, useEffect } from 'react';
export default function WindowTracker() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWindowWidth(window.innerWidth);
// Attach listener
window.addEventListener('resize', handleResize);
// Cleanup: Remove listener when component unmounts or before re-running
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <p>Window width: {windowWidth}px</p>;
}
4. React 18 Strict Mode Double-Mounting
In React 18 development mode with React.StrictMode, React intentionally mounts, unmounts, and re-mounts every component to verify cleanup integrity. If your effect does not clean up properly, you will catch bugs early!
Key Takeaways
useEffectsynchronizes components with external systems.- The dependency array dictates re-execution conditions.
- Always provide cleanup functions for subscriptions, intervals, and event listeners.
In Part 17, we explore the useRef Hook for DOM access and mutable instance variables!

