One thing React emphasizes is harmonization: cross-browser for React web, cross-platform for React Native. But the event system actually takes this concept one step further by having an (almost) identical event processing system for both React web and React Native. That’s right: both DOM and native events are treated using — minus a little bit of pre-processing —the exact same code. How does React pull off this magic trick? This could be the subject of an article — if not several — in itself, so let’s try to be brief.

Welcome to the magical world of Fiber

What happens when an app updates (let’s say, after clicking a button)? New information propagates, and the app has to be rendered again with it. Now, the core idea behind React (web or native) is to cut this very process into two separate phases: “reconciliation” — where React calculates differences and decides what updates are needed — and “rendering” — where the updates are actually applied. See where that leads us? You’re right. The “reconciliation” phase does not care about how or where the rendering is done, only about what should be rendered. Consequently, the same process can be used for both React Native and React web. The only remaining task to be done is plugging in the appropriate rendering engine.

Event processing is part of the “reconciliation” phase, and thus take place in the same abstract world, where browser events and DOM components are no different from native events and components. What does that world look like? It might be a little complex to picture, since we are so used to thinking in terms of visible, tangible objects, but in this parallel universe, each and every component becomes a Fiber . Indeed, as the React reconciliation algorithm does not care about how components are rendered but only about what changed between two render iterations, components themselves do not matter. Only the work that has to be done to go from the previous state of the component to the new state matters (that work can also be no operation, if no changes happened). And that’s what a Fiber is: not a physical entity but a unit of work, a small step in the grand scheme of the reconciliation process.

For those whose curiosity has been spiked by the previous introduction to Fiber s, I advise you to learn more on Fiber and React Fiber! This fun video presentation by Lin Clark is a good start. For everyone else, do not worry: understanding Fiber is absolutely not required to grasp the rest of this article (the switch to Fiber is rather recent, and the event management system did not undergo any major changes in the process anyway). The thing to remember is this: React works in an “abstract world” where updates are made independently of the physical representation of the component: the multiple “real worlds” (the browser, your phone…) where components are rendered are but projections of that unique, device-independent universe. Event handling is no different, and pretty much everything happens in this “abstract world” —whether the event initially came from the DOM or from native, it does not matter.

In the case of event handling, the “listening, normalizing, & re-emitting” phase exists precisely for the purpose of transforming real events and components into their abstract counterparts. It captures native events coming from components, and turns them into what React calls a topLevelType associated with a Fiber . As a result, native events and components themselves are effectively invisible to the downstream event processing system, and no handlers are installed in the “real” environment: everything takes place in the virtual DOM.

Receiving (listening to) events

Alright, looking at the above drawing, it seems that in every case the event handling starts with a listening phase. This is little surprising. After all, many of us are used to having to define our own custom listeners in our applications — because we want it to react only to click and not mousescroll for example. But why would React itself need to listen to all events? It’s becase events appear in their “natural” environment: the DOM for web applications, and native on your mobile device. React, be it in its web or native flavor, is a tool built on top of these fundamental environments. As a result, events do not naturally go through React, and it has to actively listen to them.

Receiving events: React web

For React web, the process is fairly simple and uses top-level delegation. This means that React listens to every event at the document level, which has an interesting implication: by the time any React related code is executed, events have already gone through a first capture/bubbling cycle across the DOM tree.

After receiving that event from the browser, React performs an additional cross-browser harmonization step. As a workaround for browsers having different names for what is effectively the same event, React defines topLevelTypes that are wrappers around browser-specific events. For instance, transitionEnd , webkitTransitionEnd , MozTransitionEnd and oTransitionEnd all become topAnimationEnd — effectively alleviating part of the pain of designing cross-browser applications via consolidation.

Receiving events: React Native

For React Native, events are received over the bridge that links native code with React. In short, whenever a View is created, React also passes its ID number over to native, so as to be able to receive all events related to that element. Again, slight modifications are performed before passing the (touch) event downstream, including adding the touches and changedTouches arrays to the event in order to make it W3 compliant.

From now on, in order to differentiate them for the SyntheticEvents that will be introduced later, we will refer to what we have called “events” (i.e. event objects, coming from either native or the browser, that underwent slight modifications) as “native events.”

The innards of React’s event management system

We now have our native events, harmonized across platforms and browsers. Great! We are now ready to start the real work: passing these events to the appropriate callback(s). Such is the duty of React’s event system. Let’s take a closer look.