in the previous three articles, we described the composition and life cycle of react components, and the mechanism of setState. This time let's talk about the handling of React events.
1. Native event system
We usually monitor the real DOM. For example, 🌰, we want to listen for the click event of the button, so we can bind the event and the corresponding callback function to the button DOM. Unfortunately, if the page is complex and the frequency of event processing is high, it is a test for the performance of the web page.
2.React event system
react's event handling, no matter how dazzling it is, will eventually return to the original event system, but its encapsulation is elegant. Let's go straight to the conclusion:
- React implements the SyntheticEvent layer to handle events
What does
mean? In detail, React does not correspond events to Dom one by one like native events, but binds all events to the document of the web page, processes and distributes them through a unified event listener, finds the corresponding callback function and executes it. According to the official documentation, the event handler will pass an instance of SyntheticEvent, so let's take a look at SyntheticEvent.
3.SyntheticEvent
1. Event registration
as mentioned above, since React handles events uniformly, you must first need to register the event trigger function written by the programmer. So where is this process carried out? Because we are "binding" events to "component DOM", such as a click event:
<Component onClick={this.handleClick}/>
undefined
React has already started event handling through the _ updateDOMProperties
method inside mountCompoent
when the component is mounted. In this method, the enqueuePutListener
method is executed to register the event:
The listenTo
method calls the following two functions:
- trapBubbledEvent
- trapCapturedEvent
readers familiar with the native event system will know from the English translation that the two functions are used to deal with event capture and event bubbling. The specific processing logic is not analyzed, let's look directly inside these two functions:
the target
in the above code, that is, document
, also see the familiar document.addEventListener
and document.removeEventListener
. It is this unified event binding that reduces memory overhead.
2. Event Storage
the event callback function we wrote needs to be stored after it is registered so that it can be called back when triggered. The entry for storage is EventPluginHub.putListener
function:
it can be seen that all callback functions are stored in listenerBank
as a two-dimensional array, and are managed according to the component's corresponding key
.
3. Event distribution
Now that we know about event registration and event storage, let's take a look at how React distributes events and finds the corresponding callback function and executes when the event is triggered. The distribution entry is located at handleTopLevelImpl
of ReactDOMEventListener.js
:
the above code clarifies the process: because the execution of the event callback function may lead to changes in the DOM structure, React first stores the current structure as an array and traverses the execution in turn. The _ handleTopLevel
of the above function finally handles the callback function. Take a look at the source code:
A new role appears in the
code: EventPluginHub.extractEvents
. Referring to the relevant materials, we know that the extractEvents
method is used to synthesize events, that is, to synthesize instances of different cross-browser SyntheticEvent
objects, such as SyntheticClickEvent
, depending on the event type. And EventPluginHub
is the tool plug-in used by React for compositing events:
you can see that React will use different functional plug-ins for different events, all of which are used internally through dependency injection. The process of synthesizing events in React is very tedious, but it can be summarized that the inner part of the extractEvents
function is mainly through the switch
function to distinguish the event types and call different plug-ins to deal with them, thus generating SyntheticEvent
instances. Students who are interested can understand for themselves.
4. Event handling
The idea of
React handling events is similar to that of setState
, both using batch processing. In the handleTopLevel
method above, we see that the runEventQueueInBatch
method is finally executed:
//事件进入队列
EventPluginHub.enqueueEvents(events);
//...
EventPluginHub.processEventQueue(false);
undefined
look at processEventQueue
:
the above code iterates through the events in the queue and enters executeDispatchesAndReleaseSimulated
:
event.constructor.release(event);
undefined
this line of code removes the React composition event release, reducing memory overhead. The core entry for event handling is executeDispatchesInOrder
:
var dispatchListeners = event._dispatchListeners;
var dispatchInstances = event._dispatchInstances;
executeDispatch(event, simulated, dispatchListeners[i], dispatchInstances[i]);
undefined
these are the three important lines of code. dispatchListeners
is the event callback function, and dispatchInstances
is the corresponding component. Pass these parameters into executeDispatch
:
function executeDispatch(event, simulated, listener, inst) {
var type = event.type || 'unknown-event';
ReactErrorUtils.invokeGuardedCallback(type, listener, event);
}
undefined
and invokeGuardedCallback
is quite simple:
function invokeGuardedCallback(name, func, a) {
func(a);
}
undefined
the func (a)
above is actually listener (event)
, and further up, it is dispatchListeners (dispatchInstances)
, which explains why our React event callback function can get the native event.
4. Summary
React event system has done a lot of work to be compatible with various versions of browsers. We don't have to bother to study how these are implemented. Different from native events, React unifies rather than decentralized storage and management of events, generates synthetic events internally after capturing events to improve browser compatibility, and then destroys and releases memory after executing callback functions, thus greatly improving the response performance of web pages.