Normally, React developers clean up event listeners by manually calling removeEventListener
in a useEffect
cleanup. But there’s a cleaner, more modern way: using AbortController to automatically handle cleanup without explicit unbinding.
Traditional Event Listener Setup
Here’s the classic pattern you’re probably using already:
useEffect(() => {
const handleEsc = (e) => {
if (e.key === "Escape") {
onClose();
}
};
window.addEventListener("keydown", handleEsc);
return () => {
window.removeEventListener("keydown", handleEsc);
};
}, []);
Cleaner Alternative Using AbortController
Here’s how to refactor it to use an AbortController instead:
useEffect(() => {
const controller = new AbortController();
const { signal } = controller;
const handleEsc = (e) => {
if (e.key === "Escape") {
onClose();
}
};
window.addEventListener("keydown", handleEsc, { signal });
return () => controller.abort();
}, []);
How It Works
When you pass the signal
to addEventListener
, the browser automatically removes the listener when controller.abort()
is called during the effect's cleanup. This reduces boilerplate and risk of bugs from missing cleanups.
Pros and Cons
✅ Pros
- Automatic, cleaner cleanup without manual unbinding
- Reduced chance of memory leaks
- Better readability and modern browser support
⚠️ Cons
- Requires relatively modern browsers (Chrome 88+, Firefox 85+)
- Can seem unfamiliar to some teams at first
🚀 Alternatives
- Custom
useEventListener
hooks (e.g., react-use) - Traditional add/remove patterns if older browser support is required
Summary
AbortController gives you a more streamlined way to manage event listeners inside React hooks. Cleaner code, fewer bugs, and a better mental model. Worth adopting if your project targets modern browsers.
For a much more extensive guide on getting the most out of React portals, check out my full 24-page PDF file on Gumroad. It's available for just $10:
Using React Portals Like a Pro.
If you found this useful, you can support me here: buymeacoffee.com/hexshift ☕
Top comments (0)