How Events Work in React?
How React handle Events, how things work behind the scene
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.
During the Capturing and Bubbling Phase, the Event really goes through EVERY SINGLE CHILD and PARENT elements, one by one.
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.