DEV Community

Mad Devs for Mad Devs

Posted on • Edited on

A Bit about Event Delegation in React

Alt Text

Unfortunately, in our modern world, there is no way to delve into the little things and how frameworks work.

We use many tools and like how easy it is to work with them. And most importantly, these tools solve our problems. What else do you need? Of course, the story ends here. How little is needed for happiness.

But when you implement something on pure JS, you begin to wonder how those frameworks and tools solve certain problems.

In this article, we will consider event delegation and what it is for. How it can help you in understanding the mechanisms of the framework, and maybe even in improving your decisions in pure JS.

What is an Event Delegation?

You have probably already encountered delegation of authority and tasks. The meaning of this word is very important, isn’t it? And the main point is in centralizing decision-making, thereby reducing the number of decision-making points. This is the work of a leader.

Perhaps the key points of delegation:

  • Centralization (which makes it possible to monitor events)
  • Tracking (from whom the event came)
  • Filtering (decide to react or not)

In fact, you do not handle an event on each child DOM element, but handle them on some parent DOM element and then decide what to do and how.

Event delegation - is a method of attaching event handlers not to the elements from which you actually want to handle events, but to a higher-level element.

When to apply?

  1. In any case, when you work with a large number of interactive elements. We get a lot of elements that can be removed and added quite intensively. If you accidentally did not clear the events of an element that was previously removed from the DOM by any line of code, you will get zombies that can eat up the memory.

  2. The solution to the problem of handling events in parent elements with a large nesting of child elements. For example, if you click on the most nested child element, click events will be triggered on each of the parent elements. And here you can avoid using e.stopPropagation(). This is why it is not recommended to use event chain interruption in handlers, since if you need to handle an event on the parent component, then you will not succeed.

How is event delegation applied in React?

Actually, you are watching a very good picture. There are practices that have long been applied that really solve problems, and you most often see their usage in high-quality and recommended products. These are kind of design patterns.

Let’s see how React applies Event delegation

import React, { Component } from 'react';
import { render } from 'react-dom';
import List from './List';
import ListItem from './ListItem';
import './style.css';

class App extends Component {
  constructor() {
super();
this.state = {
  name: 'React'
};
  }

  render() {
    return (
  <div>
    <List>
      <ListItem>0</ListItem>
      <ListItem>1</ListItem>
      <ListItem>2</ListItem>
      <ListItem>3</ListItem>
    </List>
  </div>
);
  }
}

render(<App />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

First, open the Chrome Developer Tools and find the list item.

Alt Text

Highlight this list item in the DOM and go to the Event Listeners tab.

Alt Text

If you expand the list of click event handlers, you will notice that React-DOM has created two handlers:

  • One on our element selected in the DOM
  • And one event handler for the DOM document object globally

Hmm … you think, every element has a handler, in this case, where are the pros of Event Delegation?

That’s a fair question, but in each case you need to dig down. Let’s go deeper and expand the property tree of the <li> element

Alt Text

What do we see? The name of the noop function hints that this is a stub. And most importantly, this stub exists in a single, global instance, and when you delete an item from the DOM, you can easily remove the element.removeEventListener(‘click’, noop) event. Yes, this slightly eliminates the effect of Event Delegation, but if you search the Internet, you will find the answer to this question. I’ll save your time — this decision is associated with a bug in iOS Safari.

A bit about the bug in iOS Safari

For each so-called “bug”, because it violates our usual use case, there is a certain reason. Because this bug can be the result of an architectural solution and hardware capabilities.

It turns out that Safari on the iPhone does not support event delegation for click events, unless click occurs on a link or text field.

Nevertheless, Apple engineers could not be so wrong, here the matter is something else. There must be some reasons for this behavior. The true reason is not known, but perhaps — this is a memory management problem. Apparently, giving all the elements on the page the ability to respond to clicks requires too many resources, and Apple engineers decided to disable this possibility.

This fact is, of course, a serious problem for web pages with a high degree of user interaction. This is an annoying fact, but, fortunately, there is a workaround.

You must make the element clickable by providing it with its own onclick event handler. This handler can be empty, while it is present, any element will be clickable.

document.onclick = function (e) {
  // click logic here
}
div.onclick = function () {} // empty event handler
Enter fullscreen mode Exit fullscreen mode

We still handle the event at the document level, but add an empty event handler to the div that we want to click. Now suddenly a div becomes clickable, the event passed to the document and is processed correctly.

The only trick is that we have to repeat this every time we change the div. After the old div has been removed from the DOM and a new one has been added, the onclick event handler also needs to be reinstalled.

Now you know the answer to the question: Where did the noop() handler come from for the li element?

You can also notice the mention of a safari bug in the source code React

Alt Text

Fun fact, but //TODO: Only do this for the relevant Safaris maybe? hints that it would be nice to use this trick only on bug-prone versions of Safari. Since we see the ubiquitous installation of noop for those elements that require a click event, it means that no mechanism has yet been added to narrow the place of usage of this trick.

This fact, of course, does not improve the mood of the developer, since it still creates a load on the use of memory on a page with many components, which suggests receiving a feedback from the user in the form of a click.

Let’s back to the Event Delegation topic in React

So, we found out why the noop() event handler is needed. And now we can understand why the event is handled globally on document object.

Alt Text

Event Delegation is an important event processing design pattern. This is where the magic of Event Delegation is going on.

Let’s take a look at the event handling method in the React source.

Alt Text

And if we delve deeper into this super-method in the React source, you can see the following picture:

Alt Text

As you can see, the basic logic for determining the element that generated the event, as well as throwing the event through the React architecture, is done below.

And if we look, purely from interest, at the getEventTarget function, we will see how much we need to consider of moments before choosing the right element, which is suitable as the source of the event.

Alt Text

As a result, you have to pay for the convenience in handling events with a more complex code scheme. But if you look at the hell of the handlers that could wait for the developer, then nevertheless the Event Delegation rules. The main thing is to understand the general pattern, and its usage is a matter of technology.

Conclusion

After reading this article, you now know:

  • What is Event Delegation
  • How it works in general in React
  • Why you need a noop click event handler
  • The details of the so-called bug in iOS Safari
  • The implementation of Event Delegation is a centralized event processing pattern.

I hope you learned something interesting for yourself, and if not, it means you may have consolidated your knowledge.

Previously published at maddevs.io.

Top comments (0)