How React Uses Event Delegation Pattern Internally to Boost Performance


If you've ever wondered how React manages to handle events so efficiently, even in large applications, the secret lies in a clever technique called event delegation
Instead of attaching events to each child element, we attach a single event to a common parent element. When an event is triggered on a child element, the DOM event bubbling mechanism triggers the parent event handler. We can then execute our logic based on the event target that originally triggered the event.
Benefits of the event delegation:
Instead of attaching 100 events to a list of buttons, we can apply just one event to a parent element. This uses less memory and helps our application load faster.
A major benefit is that if your list is dynamic, meaning new items are added or removed at any time, you don't need to attach or remove event listeners for each new or deleted element.
Adding and removing listeners dynamically when elements are created or destroyed leads to unnecessary computations. Event delegation prevents this, optimizing our app.
We can manage all events from one place, which means we only need to write our event logic in a single handler instead of multiple handlers. This results in better maintainability and simpler event handling.
Points to be noted:
When handling multiple events in the common event handler, we have to be careful about managing the event target
Event delegation is possible due to the DOM event bubbling mechanism, but the problem is that not all the events can be bubbled. Non-bubbling events include
focus
,blur
,scroll
,mouseenter
,mouseleave
,resize
, etc.
Example:
const todos = [
{ id: 1, text: "Buy groceries", completed: false },
{ id: 2, text: "Walk the dog", completed: true },
{ id: 3, text: "Read a book", completed: false }
];
const todoList = document.getElementById('todo-list');
todoList.addEventListener("click", event => {
if (event.target.classList.contains("todo")) {
const id = Number(event.target.dataset.id);
const todo = todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
renderTodos();
}
}
});
How React JS internally utilizes event delegation:
React complete events ecosystem based on the event delegation. The single event handler has already applied to the root container of the React application from where it starts rendering the app.
This single event handler on the root container captures all the bubbled events from the nested DOM elements. React has an internal system that helps it identify which component element triggered the event and determines the appropriate event handler to execute for that element.
React passes the synthetic event object as a parameter to the event handler while executing it. A synthetic event is simply a cross browser wrapper around the browser's native event. This single event handler on the root helps avoid the significant overhead of managing events on individual components, which also improves performance and maintainability.
Conclusion:
The event delegation pattern in JavaScript is very useful, not just for frameworks but also for vanilla JavaScript apps. The basic maths says that with fewer event listeners, your application uses less memory, which helps it load faster.
Subscribe to my newsletter
Read articles from Muhammad Abubakar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Muhammad Abubakar
Muhammad Abubakar
A Senior Software Engineer, Who Loves learning Software Engineering Internals, having core mastery of Frontend, but a keen interest in backend, infra, and devOps.