How to Cleanup Event Listeners in React
Be a good citizen. Always cleanup your event listeners.
Aug 23, 2019 • 4 Minute Read
What Is an Event Listener?
When building a UI in React, you'll likely have many events that you want to listen to. That means you'll want to clean them up too. So, what are events, listeners, and why do we want to clean them up?
An event is, generically, something that a user does or the browser does. A user might click a button or resize a window. The browser might receive a message from a server or worker process.
An event listener is set up when we write code that defines the kind of event that might occur and the code that should run when that event is eventually detected. Events are asynchronous, so event listeners are defined as callbacks to those events.
Why Cleanup?
Callbacks are defined to listen to events over time. They're declared and then they stick around, listening. But there usually comes a time when they can stop listening. And if they're not needed anymore, they should be cleaned up. This is because keeping event listeners around isn't free. It takes memory and some processing power from the browser and the host computer.
What makes this more important is that React components will often be re-rendered, and the code to set up event listeners will have the opportunity to run many times. This can create errors by setting up multiple listeners where we're actually expecting a single listener run per event occurrence.
Additionally, React-based UIs are often used in single-page apps that exist within long-lived browser sessions. This creates an environment where memory leaks can become serious more often.
Built-in Listener Cleanup
It is possible that we are using event listeners without really thinking them as such. This is because it's such a natural part of how UIs work and what we write to make them function. For instance, we might have a Form that has a button that captures a click event:
import React from 'react'
function Form() {
function handleClick(evt) {
console.log('do submitting stuff')
}
return (
// form stuff...
<button onClick={handleClick}>Submit</button>
)
}
Thankfully, when the Form component is unmounted and leaves the DOM, the click handler will be automatically removed as well. React takes care of it. It's built in, and you don't have to worry about it. Done.
Manual Event Listener Cleanup
For anything that's not a built-in React element-based event listener, you'll need to do extra work for the setup and for the cleanup. Let's say that our Form component now listens for window resize events. It could look like this:
import React from 'react'
function Form() {
React.useEffect(function setupListener() {
function handleResize() {
console.log('Do resize stuff')
}
window.addEventListener('resize', handleResize)
return function cleanupListener() {
window.removeEventListener('resize', handleResize)
}
})
return // render...
}
Note that the cleanupListener function that the React.useEffect callback can returns will be called at the time that this React component is unmounted and is the place to do cleanup. This happens via window.removeEventListener. The removeEventListener call must reference the exact same function in the removeEventListener call to remove the listener correctly.
If you're not using React hooks, you can use the class-based React component lifecycle methods instead. Setup is done inside componentDidMount and cleanup would be done inside componentWillUnmount.
Always Cleanup
Be a good citizen. Always cleanup your event listeners. Do this with window.removeEventListener when your component unmounts. By cleaning up, you'll avoid listening to events multiple times and memory leaks. Save the planet -- clean up your event listeners.