When and why to remove event listeners in JavaScript.

When and why to remove event listeners in JavaScript.

What are events in JavaScript?

Events are an essential part of many programming languages. There are also whole software designs around events, e.g., Event-Driven Architecture (EDA).

The event system behind JavaScript registers handlers and binds them to specific events. Events could be something like mouseclick, touch, or keydown. A handler is a simple function.

The process of binding a handler to a specific event is called registering. Any registered event should be cleaned up when not needed anymore. There are several reasons for that. First, events can easily cause memory leaks, and second, it is also simple to create incorrect code with events.

How to register events in JavaScript

Events can be registered in multiple ways. First, they can be attached directly to an element.

<button type="button" onclick="clickToRemove(event)">
  click me
</button>

Second, they can be attached programmatically:

// globally to the current document or window
document.addEventListener("click", handler);

// to a certain element
const element = document.createElement("div");
element.addEventListener("click", handler);

// and there's another syntax you might encounter, don't use it!
element.onclick = handler;

Be careful with the latter syntax. It's not recommended to use it anymore. I am only referencing it here to make you aware of that fact.

How to remove events in JavaScript

Removing works similar to registering. Instead of using addEventListener we use removeEventListener.

For instance:

// remove a global event
document.removeEventListener("click", handler);

// to a certain element
const element = document.createElement("div");
element.removeEventListener("click", handler);

Note: The handler should be a reference to the same function that we have registered before. It is also possible to remove them without reference, but it is a little bit more complex:

const element = document.querySelector("button");

// get all events from an element
const events = getEventListeners(element);

// remove the first click listener
element.removeEventListener("click", events["click"][0].listener);

Since we can have more than one listener per event, the getEventListeners-function returns an object with all possible events, and this object holds an array of our listeners.

Why and when should I remove event listeners?

TLDR; Always remove event listeners when you don't plan on using them any longer.

Creating a memory leak:

const myVar = {}; // <- this is an object from our backend
const handler = () => {
  doSomethingWith(myVar);
}

document.addEventListener("keyup", handler);

Even after removing the element from our DOM, we keep a reference to myVar, since we never clean up the listener. The solution is to clean up the listener when we don't need it anymore. There are valid situations where you don't have to remove the listener, for example when you add a listener to your document that you want to keep around until the user leaves your website. Then removing the listener might not be necessary.

Keeping events alive

Sometimes we add a click listener to an element that is not needed all the time (e.g., outside click handlers for modals).

Since we only need the listener for our modal, it should be removed whenever the user cannot interact with our modal any longer.

The same is true for any element that can be toggled as well as animations on elements. As a matter of fact, this pattern is so common that addEventListener has a one-off functionality built-in:

element.addEventListener("click", handler, {once: true});

Now, the event listener will remove itself once it has been fired. This is useful for one-time animations or close-handlers on modals.

In a library with a life-cycle

In libraries or frameworks like React or Angular, we have components with a life-cycle (e.g., mounting and unmounting of components).

Handling events in these environments is a little bit easier: Remove events whenever you're unmounting a component.

This will ensure that your event handler can be garbage collected and thus removed from memory.

That's all, folks! Thanks for reading.


Title Image from Unsplash: unsplash.com/photos/exfrR9KkzlE