How Events Work in React?

HowardHoward
5 min read

Welcome

Hi there! It's Howard again. πŸ™‹β€β™‚οΈ

In this article, we will talk about how events work in browsers and React.

Let's get started.


Event Propagation & Delegation

First, let's consider this tree of elements.

It's the DOM tree, not the Fiber tree or React elements tree (Virtual DOM).

πŸ‘‰ Now, let's say some Event happens, for example: A CLICK to one of the 3 buttons.

Here's what's gonna happen in the browser.

As soon as the event fires, a new event Object will be created. 😁

BUTit will not be created where the Click actually happened (the button element)

INSTEAD, this event object will be created at the ROOT of the Document - the very TOP of the Tree.

From there, the event will then travel DOWN the entire tree, during the so-called CAPTURING PHASE.

All the way, until it reached the TARGET ELEMENT.

Target Element is simply the element on which the event was actually first triggered.

At the Target Element we can place an Event Handler function on that Element.

Then, immediately AFTER the target element has been reached.

The Event object travels all the way back up the Entire tree, during the so-called BUBBLING PHASE.

There are two Very Important Things to Understand about this process.

  1. During the Capturing and Bubbling Phase, the Event really goes through EVERY SINGLE CHILD and PARENT elements, one by one.

  2. By default, event handlers listen to events NOT ONLY on the Target Element but ALSO during the BUBBLING PHASE.

πŸ‘‰ Let's put these 2 things together.

It means that every single event handler in a parent element will also be executed during the BUBBLING PHASE. As long as it's also listening for the SAME TYPE OF EVENT.

πŸ˜‡ To better illustrate, if we add another click event handler to the header element.

πŸ‘‰ During the process, both handlers at the target element, and theheader would be executed when the click happens.

Sometimes, we actually DON'T WANT that behavior ❌

βœ… We can PREVENT event from bubbling up further with e.stopPropagation() - worked with both JavaScript and React.

Based on the fact that Event bubbling like this, allows us developers to implement a very common technique called Event Delegation.

πŸ‘‰ With event delegation, we can handleevents for multiple elements centrally in ONE SINGLE parent element.

Imagine, instead of 3 buttons, we have 100 buttons or even more.

If we want to listen to click event on all of them, so each button would have its own copy of the event handler function. Which could become problematic for application performance and memory usage.

πŸ‘‰ Event Delegation is better for performance and memory, because it needs ONLY ONE handler function.

By using Event delegation, we can simply add just ONE handler function to the FIRST direct parent element of these buttons.

Then, when click event happens on one of the buttons, event will bubble up to the .options div element in the example.

Where we can then use the event.target property to check whether the event originated from one of the buttons or not.

If it did, in other words, the target is one of the <button>s, we handle the event in this Central event handler function. βœ…


How React Handles Events?

Let's keep consider the same DOM tree. (Not Component Tree)

When we attach an Event handler to a button in React.

<button 
    className="btn" 
    onClick={() => setLoading(true)} 
/>

Intuitively, this is what you might think here's what React actually registers event handler behind the scene. It might looks something like

document.querySelector(".btn")
.addEventHandler("click", () => setLoading(true))

However, internally, that's NOT what React does. πŸ›‘

βœ… Here's what happens Internally

document.querySelector("#root")
.addEventHandler("click", () => setLoading(true))

React registers this and all other event handler functions to the ROOT DOM container.

This is where all events are handled.

The root container is simply the DOM element in which the React app is displayed.

The way React does all of this behind the scenes is way more complicated than this.

It's not worth diving into it here.

React physically registers ONE event handler function per event type at the root node of the Fiber tree during the Render phase.

Therefore, if we have multiple onClick handlers on our code, React will somehow BUNDLE them all together and just add ONE BIG onClick handler to the root node of Fiber tree.

This is another important function of the Fiber tree.

Behind the scenes, React perform Event Delegation for ALL Events in our applications.

πŸ‘‰ React delegates all events to the Root DOM Container and handle everything there, not in the place we thought we registered them.

πŸ‘‰ Finally, once the process is done, event continuing bubbling up until it disappears into nowhere.


Synthetic Events

We talked a lot about events object.

Let's have a quick look at it.

Whenever we declared an event like this one, React gives us access to the event object.

<input onChange={(e) => setName(e.target.value)} />

This event is actually different from vanilla Javascript.

In Javascript, we simply get access to the Native Event Object.

For instance: Keyboard Event, Mouse Event, Pointer Event...

On the other hand, React gives us something called Synthetic Event.

πŸ‘‰ It's a wrapper around DOM's native event object. So it's very similar to a native event, but they just add or change some functionalities on top of them.

πŸ‘‰ Has same interface as native event objects, like stopPropagation or preventDefault

πŸ‘‰ Fixes some browser inconsistencies, so events work exactly the same way with all browsers.

πŸ‘‰ Most synthetic events bubble (focus, blur, change,...) except for scroll event.

Reference resources: Jonas Schmedtmann & React Documentation.

4
Subscribe to my newsletter

Read articles from Howard directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Howard
Howard

πŸ™‹β€β™‚οΈ I'm a Software Engineer, Voracious Reader, Writer (tech, productivity, mindset), LOVE Fitness, Piano, Running.πŸ’» Started coding professionally in 2020 as a full-time Frontend engineer. βš—οΈ I make things in the messy world of JS, Computer Science, and Software Engineering more digestible. Or I would like to say β€œDistilled” πŸ“Ή Documenting my learning journey, and working experience along the way. Share how I learn and build my personal projects.