React Event System
I just do a few anatomy of react source code on its event system, and this is not the latest source code coz Facebook has already updated React into a new one featured with Fiber which will optimize React’s reaction towards user’s input and output while React Component is under its own life cycle process.
1 | render() { |
_UpdateDOMProperties [At the very first]
In file ReactDOMComponent.js
, _UpdateDOMProperties
will be triggered when mountComponent and updateCompoennt. It’s just like appending properties or updating properties during its life cycle.
Let’s jump to the point, enqueuePutListener
. This is responsible for registering event.
So go to definition of
enqueuePutListener
1 | function enqueuePutListener(inst, registrationName, listener, transaction) { |
Too much info, but what we need know is:
- This functionality traces back to instance’s ancestor until we find document. That’s why React Event is bound to document.
- Then invoking
listenTo
will register event to document. - In the end, transaction will call
putListener
to store this event, when event is triggered, React will call this event’s callback func.
Let’s dive into
listenTo
It’s defiend in file ReactBrowserEventEmitter.js
. Within listenTo
, the core is trapBubbledEvent
and trapCapturedEvent
. Bubbled is for event at the phase of bubbling, captured is for capturing. Here we just take a look at trackBubbledEvent
.
1 | trapBubbledEvent: function(topLevelType, handlerBaseName, element) { |
As you can see in code snippet above, EventListener
does only one thing, listen
. And if you go deeper to see what exactly EventListener.listen does, you will finally see something you’re familiar with. (addEventListener/attachEvent)
1 | listen: function listen(target, eventType, callback) { |
Time to store event
In aforementioned section, we have already listened
event, but where and how do we process event’s listener(AKA event callback). Here is the answer. You can find putListener
in functionality enqueuePutListener
.
1 | function putListener() { |
EventPluginHub
does do something hub will do.
1 | // EventPluginHub |
See, EventPluginHub stores event listener in listenerBank.
How Is Event Dispatched
You have already seen that ReactEventListener.dispatchEvent.bind(null, topLevelType)
is added as event callback when it’s in the phase of trapBubbledEvent
. So in file ReactEventListener
, dispatchEvent
will be the entrance of event dispatch.
1 | // In ReactEventListener.js |
We still batch process event as you can see ReactUpdates.batchedUpdates(handleTopLevelImpl, bookKeeping);
is defined within dispatchEvent.
Therefore, handleTopLevelImpl
is the core.
1 | function handleTopLevelImpl(bookKeeping) { |
The important thing in handleTopLevelImpl
is collecting event target’s ancestors and saving them locally. That’s why React Synthetic Event has its own bubbling system.
CONTINUE
ReactEventListener._handleTopLevel
actually is using ReactBrowserEventEmitter
‘s handleTopLevel, let check that out:
1 | handleTopLevel: function( |
It’s crystal
clear that handleTopLevel does two things:
- Construct React Synthetic Event.
- Batch run events.
How Synthetic Event Is Constructed?
1 | extractEvents: function( |
Due to limited time, I will write a new post to talk detailed process while constructing react synthetic events. But here we need to be clear about some points:
- When constructing its Synthetic Event, React use a Object pool mechanism which will dramatically reduce the time spent of object creation and destroy, so as to largely improve its performance.
- Event is based on templates. Here,
EventPluginRegistry
contains five plugins: SimpleEventPlugin, EnterLeaveEventPlugin, ChangeEventPlugin, SelectEventPlugin, BeforeInputEventPlugin. They have their own processing respectively.
After Synthetic Event Is Constructed
Then we runEventQueueInBatch(events);
. Again, I will upload a new post to elaborate on this topic.