Explore React synthetic events
1, What is a composite event
React synthetic event is an event object that can simulate all the capabilities of native DOM events, that is, the cross browser wrapper of browser native events. It defines synthetic events according to W3C specification, is compatible with all browsers, and has the same interface as browser native events.
In React, all events are synthetic, not native DOM events, but DOM events can be obtained through the e.nativeEvent attribute. For example:
const button = <button onClick={handleClick}>react Button</button> const handleClick = (e) => console.log(e.nativeEvent); //Native event object Copy code
When learning a new knowledge, we must know why this technology appears.
So why does React use composite events? It has three main purposes:
Browser compatibility to achieve better cross platform
React adopts the top-level event proxy mechanism, which can ensure bubble consistency and can be executed across browsers. The synthetic events provided by react are used to smooth out the differences between different browser event objects and simulate synthetic events from different platform events.
Avoid garbage collection
Event objects may be frequently created and recycled. Therefore, React introduces the event pool to obtain or release event objects in the event pool. That is, the React event object will not be released, but will be stored in an array. When the event is triggered, it will pop up from the array to avoid frequent creation and destruction (garbage collection).
Facilitate unified incident management and transaction mechanism
This article will not introduce the source code. If you are interested in the source code of the specific implementation, you can refer to "react synthetic event".
2, Native event review
JavaScript event models are mainly divided into three types: original event model (DOM0), DOM2 event model and IE event model.
1.DOM0 event model
Also known as the original event model, in this model, events will not propagate, that is, there is no concept of event flow. The event binding listening function is relatively simple. There are two ways:
//There are three kinds of direct binding of HTML code: <button type='button' id="test" onclick="fun()"/> //Specify the attribute value through JS code: var btn = document.getElementById('.test'); btn.onclick = fun; //Remove listener function: btn.onclick = null; Copy code
Advantages: strong compatibility and support for all browsers
Disadvantages: logic and display are not separated; Only one listening function for the same event can be bound. The same event registered later will overwrite the previously registered event.
2.2 event model
The standard model developed by W3C is supported by modern browsers (except IE6-8). In this event model, an event has three processes:
Event capture phase. The event propagates down from the document to the target element. Check whether the passing nodes are bound to the event listening function in turn. If so, execute it.
Event processing phase (target phase). The event reaches the target element and triggers the listening function of the target element.
Event bubbling phase. The event bubbles from the target element to the document, and then check whether the passing node is bound with the event listening function. If so, execute it.
//The event binding listening function is as follows: addEventListener(eventType, handler, useCapture) //The method to remove the listener function from the event is as follows: removeEventListener(eventType, handler, useCapture) Copy code
3.IE event model
IE event model has two processes:
Event processing phase (target phase). The event reaches the target element and triggers the listening function of the target element.
Event bubbling phase. The event bubbles from the target element to the document, and then check whether the passing node is bound with the event listening function. If so, execute it.
//The event binding listening function is as follows: attachEvent(eventType, handler) //The method to remove the listener function from the event is as follows: detachEvent(eventType, handler) Copy code
4. Event flow
As shown in the figure above, the so-called event flow includes three stages: event capture, target stage and event bubbling. Event capture is from the outside to the inside. The red arrow in the corresponding figure indicates the part window - > document - > HTML... - > target. The target stage is the stage where the event actually occurs and is processed. Event bubbling is from the inside to the outside. It corresponds to the target - > document - > window in the figure.
Event capture
When an element triggers an event (such as onclick), the top-level object document will send out an event flow, which flows to the target element node along with the node of the DOM tree until it reaches the target element where the event actually occurs. In this process, the corresponding listening function of the event will not be triggered.
Event target
After reaching the target element, execute the corresponding processing function of the event of the target element. If the listener function is not bound, it will not be executed.
Event Bubbling
Start from the target element and propagate to the top element. If a node is bound with corresponding event handling functions on the way, these functions will be triggered once. If you want to prevent the event from bubbling, you can use e.stopPropagation() or e.cancelBubble=true (IE) to prevent the event from bubbling.
Event entrustment / event agent
A simple understanding is to delegate a response event to another element. When the child node is clicked, the click event bubbles upward. After the parent node captures the event, we judge whether it is the required node, and then process it. Its advantage is to reduce memory consumption and dynamically bind events.
3, Principle of React synthetic event
The working principle of React synthetic events can be roughly divided into two stages:
Event binding
Event trigger
Before react17, react delegated events to the document. React17 and later versions no longer delegated events to the document, but to the mounted container. This paper focuses on 16 X version of react as an example to explore the synthetic events of react. When the real dom triggers an event, the react synthetic event object is constructed, and the real event processing functions are collected according to the bubbling or captured path. In this process, the native event will be processed first, and then the react event will be processed after bubbling to the document object. Take chestnuts for example:
import React from 'react'; import './App.less'; class Test extends React.Component { parentRef: React.RefObject<any>; childRef: React.RefObject<any>; constructor(props) { super(props); this.parentRef = React.createRef(); this.childRef = React.createRef(); } componentDidMount() { document.addEventListener( 'click', () => { console.log(`document Native event capture`); }, true, ); document.addEventListener('click', () => { console.log(`document Native event bubbling`); }); this.parentRef.current.addEventListener( 'click', () => { console.log(`Parent element native event capture`); }, true, ); this.parentRef.current.addEventListener('click', () => { console.log(`Parent element native event bubbling`); }); this.childRef.current.addEventListener( 'click', () => { console.log(`Child element native event capture`); }, true, ); this.childRef.current.addEventListener('click', () => { console.log(`Child element native event bubbling`); }); } handleParentBubble = () => { console.log(`Parent element React Event Bubbling `); }; handleChildBubble = () => { console.log(`Child element React Event Bubbling `); }; handleParentCapture = () => { console.log(`Parent element React Event capture`); }; handleChileCapture = () => { console.log(`Child element React Event capture`); }; render() { return ( <div ref={this.parentRef} onClick={this.handleParentBubble} onClickCapture={this.handleParentCapture} > <div ref={this.childRef} onClick={this.handleChildBubble} onClickCapture={this.handleChileCapture} > Event handling test </div> </div> ); } } export default Test; Copy code
The case printed above is:
Note: the execution of the above cases in React17 will be different. All capture events will be executed first, and then all bubble events will be executed.
- Event binding
Through the above cases, we know the execution process of React synthetic events and native events. In fact, the two are related through a module called EventPlugin. Each plugin only processes the corresponding synthetic events. For example, onClick event corresponds to SimpleEventPlugin plugin. In this way, React will load these plugins at the beginning, Initialize some global objects through the plug-in. For example, one of the objects is registrationNameDependencies, which defines the correspondence between synthetic events and native events as follows:
{ onClick: ['click'], onClickCapture: ['click'], onChange: ['blur', 'change', 'click', 'focus', 'input', 'keydown', 'keyup', 'selectionchange'], ... } Copy code
The registrationNameModule object specifies the mapping of the React event to the corresponding plug-in plugin:
{ onClick: SimpleEventPlugin, onClickCapture: SimpleEventPlugin, onChange: ChangeEventPlugin, ... } Copy code
The plugins object is the list of the above plug-ins. For example, if the event type of the synthesized event is the type of the synthesized event that is registered in the process of the top-level rendering, it is judged according to the event type of the synthesized event that is found in the process of the synthesized event.
- Event trigger
When any event is triggered, the dispatchEvent function will be executed. For example, in the above example, when the user clicks the div of Child, it will traverse all the parent elements of this element and collect and process the events of each level of elements in turn, Construct a synthetic event object (synthetic event – that is, the default parameter event of the custom function in React, and the native event object corresponds to one of its attributes), and then form a "chain". This chain will store the synthetic events in eventQueue in turn, and then traverse eventQueue to simulate the capture and bubbling stages, Then use the runEventsInBatch method to trigger the listening events calling each item in turn. In this process, it will judge whether it is triggered in the bubbling stage or the capture stage according to the event type. For example, onClick is triggered in the bubbling stage, onClickCapture is triggered in the capture stage, and is released after the event processing is completed. SyntheticEvent object properties are as follows:
boolean bubbles boolean cancelable DOMEventTarget currentTarget boolean defaultPrevented number eventPhase boolean isTrusted DOMEvent nativeEvent // Native event object void preventDefault() boolean isDefaultPrevented() void stopPropagation() boolean isPropagationStopped() void persist() DOMEventTarget target number timeStamp string type Copy code
The pseudo code of dispatchEvent is as follows:
dispatchEvent = (event) => { const path = []; // Synthetic event chain let current = event.target; // Trigger event source while (current) { path.push(current); current = current.parentNode; // Collect step by step } // Simulate capture and bubbling phases // path = [target, div, body, html, ...] for (let i = path.length - 1; i >= 0; i--) { const targetHandler = path[i].onClickCapture; targetHandler && targetHandler(); } for (let i = 0; i < path.length; i++) { const targetHandler = path[i].onClick; targetHandler && targetHandler(); } }; Copy code
- Change event delegation (React v17.0)
Since the release of React, event delegation has been carried out automatically. When the DOM event is triggered on the document, React will find the calling component, and then the React event will "bubble" upward in the component. But in fact, the native event has bubbled out of the document level, and React has installed the event handler in it.
However, this is the difficulty of gradual upgrading.
In React 17, React will no longer attach event handlers to document s. Instead, the event handler is attached to the root DOM container of the rendered React tree:
const rootNode = document.getElementById('root'); ReactDOM.render(<App />, rootNode); Copy code
In React 16 or earlier, react executes document. For most events addEventListener(). React 17 will call RootNode at the bottom addEventListener()
4, Attention
Since event objects may be frequently created and recycled in react16 In X, the synthetic event adopts the event pool, and the synthetic events will be put into the event pool for unified management, which can reduce the memory overhead. React simulates the capture and bubbling stages by synthesizing events, so as to achieve the compatibility of different browsers. In addition, react does not recommend using native events and composite events together, which is easy to cause confusion.
Due to the change of event delegation in version 17, it is now safer to nest the old and new versions of React trees. Please note that for it to work properly, both versions must be 17 or higher, which is the root reason why it is strongly recommended to upgrade to React 17.
last
If you think this article is a little helpful to you, give it a compliment. Or you can join my development exchange group: 1025263163 learn from each other, and we will have professional technical Q & A to solve doubts
If you think this article is useful to you, please click star: http://github.crmeb.net/u/defu esteem it a favor!
PHP learning manual: https://doc.crmeb.com
Technical exchange forum: https://q.crmeb.com