![]()
Listening to window events without cleaning them up in React can cause memory leaks, unexpected behavior, and performance issues, especially when components mount and unmount frequently. This issue often arises with events like resize, scroll, keydown, or mousemove.
Common Mistake Example:
// ❌ Incorrect: No cleanup for window event listener
function App() {
React.useEffect(() => {
const handleResize = () => {
console.log("Window resized");
};
window.addEventListener("resize", handleResize); // ❌ Added without cleanup
// No cleanup function
}, []);
return <div>Resize the window</div>;
}
Issues:
- Memory Leak: Event listeners remain even after the component unmounts.
- Performance Hit: Accumulation of listeners can slow down the app.
- Unintended Behavior: Functions triggering for unmounted components.
Correct Way (Removing Event Listeners on Unmount):
function App() {
React.useEffect(() => {
const handleResize = () => {
console.log("Window resized");
};
window.addEventListener("resize", handleResize);
// ✅ Cleanup function to remove the event listener
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return <div>Resize the window</div>;
}
- Why This Works:
The cleanup function insideuseEffectensures the event listener is removed when the component unmounts.
Handling Window Events in Class Components:
class App extends React.Component {
handleResize = () => {
console.log("Window resized");
};
componentDidMount() {
window.addEventListener("resize", this.handleResize);
}
componentWillUnmount() {
// ✅ Removing event listener on unmount
window.removeEventListener("resize", this.handleResize);
}
render() {
return <div>Resize the window</div>;
}
}
- Why This Works:
componentWillUnmountis the correct lifecycle method to clean up event listeners in class components.
Common Pitfall with Multiple Event Listeners:
// ❌ Incorrect: Adding multiple event listeners without removing them
function App() {
React.useEffect(() => {
const handleScroll = () => console.log("Scrolling...");
window.addEventListener("scroll", handleScroll);
window.addEventListener("scroll", handleScroll); // ❌ Duplicate listener
// No cleanup
}, []);
return <div style={{ height: "2000px" }}>Scroll down</div>;
}
Fix:
- Ensure only one listener is added.
- Remove all listeners during cleanup.
React.useEffect(() => {
const handleScroll = () => console.log("Scrolling...");
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
Bonus Tip:
For complex event handling, consider creating a custom hook to manage window events with proper cleanup.
function useWindowEvent(eventType, callback) {
React.useEffect(() => {
window.addEventListener(eventType, callback);
return () => {
window.removeEventListener(eventType, callback);
};
}, [eventType, callback]);
}
