In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-20 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/03 Report--
What is the principle of react events? I believe many inexperienced people are at a loss about it. Therefore, this paper summarizes the causes and solutions of the problem. Through this article, I hope you can solve this problem.
A preface
Today we are going to discuss the principle of React events. In this article, I will try my best to explain the React event system clearly and clearly in a popular and concise way.
The react version we are talking about is 16.13.1, and react will have related changes to the event system after v17, which will be mentioned in the second half of the article.
Old rule, before we formally explain react, let's consider these questions (if I were an interviewer, what would you say?):
1 is the event we wrote bound to dom, and if not where?
2 Why can't our events be bound to components?
3 Why is our event manually bound to this (not in the case of the arrow function)
4 Why can't you use return false to block the default behavior of events?
5 how does react find the corresponding fiber object through the dom element?
6 onClick is bound in the bubbling phase? So is onClickCapture bound during the event capture phase?
Necessary concepts of knowledge
Before figuring out react events, there are several concepts that we must understand, because only by understanding these concepts can we better understand the nature of react processing events in the event trigger phase.
What will the JSX event become when we write about it?
Let's write a react JSX syntax with click events and see what it will look like in the end.
Class Index extends React.Component {handerClick= (value) = > console.log (value) render () {return button Click}}
Converted to React.createElement form by babel, as follows:
Babel.jpg
The final conversion to the form of fiber object is as follows:
Fiber.jpg
The memoizedProps and pendingProps on the fiber object hold our events.
What is a synthetic event?
As we saw in the previous step, we declare the location where the event is saved. But has the incident really been registered? Let's take a look at:
Let's see if this event listener is bound to the current element.
Button_event.jpg
Events bound on button
We can see that there are two events bound to button, one is the event listener on document and the other is button, but the event handler handle is not our handerClick event, but noop.
What is noop? Let's move on.
It turns out that noop points to an empty function.
Noop.jpg
Then we look at the events bound by document
Document.jpg
You can see that the click event is bound to the document.
Next, let's make trouble by adding an input input box to the demo project and binding an onChange event. Open your eyes and see what happens next.
Class Index extends React.Component {componentDidMount () {console.log (this)} handerClick= (value) = > console.log (value) handerChange= (value) = > console.log (value) render () {return button Click}}
Let's first take a look at the events bound on the input dom element
Then let's take a look at the events bound on document
8E1D3BDB-ACFB-4E49-A5FF-CF990C47A60E.jpg
We found that the onChange we bound to is not directly bound to input, but uniformly bound to document, and then our onChange is processed into many event listeners, such as blur, change, input, keydown, keyup and so on.
To sum up, we can draw a conclusion:
① the event we tied in jsx (handerClick,handerChange in demo) is not registered with the real dom at all. It is bound to be managed uniformly on document.
The click event on ② 's real dom is handled separately and has been replaced by an empty function at the bottom of the react.
③ events that we bind to react, such as onChange, on document, there may be multiple events corresponding to it.
Instead of binding all events to document at the beginning, ④ react adopts an on-demand binding, such as finding the onClick event and then binding the document click event.
So what is react event synthesis?
In react, the events we bind, such as onClick, are not native events, but React events that are composed of native events, such as click events into onClick events. For example, blur, change, input, keydown, keyup, etc., are synthesized into onChange.
What about react adopting this pattern of event composition?
On the one hand, events are bound to document unified management to prevent many events from being directly bound to native dom elements. Cause some uncontrollable situations
On the other hand, React wants to implement a full-browser framework, and in order to achieve this goal, it needs to provide a full-browser consistent event system to smooth out the differences between different browsers.
In the next article, we will describe how react does event synthesis.
The fiber Tag object corresponding to the dom element
We know how react stores our event functions and event composition causality. Next I want you to remember a type of fiber object, because it will be used later, which is very helpful for later understanding.
Let's first look at a code snippet:
Hello, my name is alien
Look at the fiber type corresponding to hello and my name is alien. Tag = 5
Then we go to the react source code to find the fiber type of this class.
/ react-reconciler/src/ReactWorkTagsq.jsexport const HostComponent = 5; / / element node
OK, let's record HostComponent and HostText for the time being. Get down here. Let's get back to the point. Let's first look at the react event composition mechanism.
Event initialization-event composition, plug-in mechanism
Next, let's take a look at how react handles event composition. First of all, we know from the above that react does not bind all events at once, but only binds click events if you find onClick in the project, and blur, change, input, keydown, keyup, etc., if you find onChange events. So in order to make the principle clear, the author divides the event principle into three parts:
1 react on how events are synthesized.
2 how the react event is bound.
3 react event triggers the process.
Event composition-event plug-in
1 necessary concepts
Let's look at a few constant relations first, which is very helpful for us to understand the principle of react events. In the explanation from the analysis, I will also talk about how these objects come from and what their specific functions are.
① namesToPlugins
The first concept: namesToPlugins installs event name-> event module plug-in mapping. The final look of namesToPlugins is as follows:
Const namesToPlugins = {SimpleEventPlugin, EnterLeaveEventPlugin, ChangeEventPlugin, SelectEventPlugin, BeforeInputEventPlugin,}
SimpleEventPlugin and other plug-ins are plug-ins that handle various event functions. For example, if you click on an event, you will find the corresponding handler for SimpleEventPlugin. Let's record it first, and as to what it does, we'll talk about it next.
② plugins
Plugins, which is the list of all the plug-ins registered above, initialized to empty.
Const plugins = [LegacySimpleEventPlugin, LegacyEnterLeaveEventPlugin,...]
③ registrationNameModules
RegistrationNameModules records the relationship between the events synthesized by React and the corresponding event plug-ins. In React, when dealing with events in props, the corresponding event plug-ins are found according to different event names, and then uniformly bound to document. For events that have not occurred before, they will not be bound, which we will talk about next. The general appearance of registrationNameModules is shown below.
{onBlur: SimpleEventPlugin, onClick: SimpleEventPlugin, onClickCapture: SimpleEventPlugin, onChange: ChangeEventPlugin, onChangeCapture: ChangeEventPlugin, onMouseEnter: EnterLeaveEventPlugin, onMouseLeave: EnterLeaveEventPlugin,...}
④ event plug-in
So the first thing we need to figure out is, what is every plug-in for SimpleEventPlugin,EnterLeaveEventPlugin? Let's take SimpleEventPlugin as an example to see what it looks like.
Const SimpleEventPlugin = {eventTypes: {'click': {/ * handle click events * / phasedRegistrationNames: {bubbled:' onClick', / / corresponding event bubbling-onClick captured:'onClickCapture' / / corresponding event capture phase-onClickCapture}, dependencies: ['click'] / / event dependency.}, 'blur': {/ * handles events that lose focus * /},.} extractEvents:function (topLevelType,targetInst,) {/ * event handlers corresponding to events in eventTypes Next, we will focus on * /}}.
First of all, the event plug-in is an object with two properties, the first extractEvents is a unified event handling function, and the second eventTypes is an object, which holds the mapping relationship between the native event name and the corresponding configuration item dispatchConfig. Because v16React events are uniformly bound to document, React uses unique event names such as onClick and onClickCapture to indicate whether the function we bind is executed in the bubbling event phase or capturing the event phase.
⑤ registrationNameDependencies
OnBlur: ['blur'], onClick: [' click'], onClickCapture: ['click'], onChange: [' blur', 'change',' click', 'focus',' input', 'keydown',' keyup', 'selectionchange'], onMouseEnter: [' mouseout', 'mouseover'], onMouseLeave: [' mouseout', 'mouseover'],.. 2 event initialization
For event composition, v16.13.1 version react uses initialization registration.
First step of react-dom/src/client/ReactDOMClientInjection.js/*: register event: * / injectEventPluginsByName ({SimpleEventPlugin: SimpleEventPlugin, EnterLeaveEventPlugin: EnterLeaveEventPlugin, ChangeEventPlugin: ChangeEventPlugin, SelectEventPlugin: SelectEventPlugin, BeforeInputEventPlugin: BeforeInputEventPlugin,})
What exactly is the use of the function injectEventPluginsByName, which is executed by default at the bottom of react. Let's simplify this function and see what it does.
Legacy-event/EventPluginRegistry.js/* Registration event plug-in * / export function injectEventPluginsByName (injectedNamesToPlugins) {for (const pluginName in injectedNamesToPlugins) {namesToPlugins [pluginName] = injectedNamesToPlugins [pluginName]} recomputePluginOrdering ()}
What injectEventPluginsByName does is simple, form the namesToPlugins above, then execute recomputePluginOrdering, and let's see what recomputePluginOrdering does next.
Const eventPluginOrder = ['SimpleEventPlugin',' EnterLeaveEventPlugin','ChangeEventPlugin','SelectEventPlugin', 'BeforeInputEventPlugin'] function recomputePluginOrdering () {for (const pluginName in namesToPlugins) {/ * find the corresponding event handling plug-in, such as SimpleEventPlugin * / const pluginModule = namesToPlugins [pluginName]; const pluginIndex = eventPluginOrder.indexOf (pluginName); / * populate the plugins array * / plugins [pluginIndex] = pluginModule } const publishedEvents = pluginModule.eventTypes; for (const eventName in publishedEvents) {/ / publishedEvents [eventName]-> eventConfig, pluginModule-> event plug-in, eventName-> event name publishEventForPlugin (published events [eventName], pluginModule,eventName,)}}]
RecomputePluginOrdering, the function is very clear, to form the plugins array mentioned above. Then there is the key function publishEventForPlugin.
/ * dispatchConfig-> native events correspond to configuration items {phasedRegistrationNames: {bubble capture},} pluginModule-> event plug-ins such as SimpleEventPlugin eventName-> native event names. * / function publishEventForPlugin (dispatchConfig,pluginModule,eventName) {eventNameDispatchConfigs [eventName] = dispatchConfig; / * event * / const phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; if (phasedRegistrationNames) {for (const phaseName in phasedRegistrationNames) {if (phasedRegistrationNames.hasOwnProperty (phaseName)) {/ / phasedRegistrationName React event name such as onClick / onClickCapture const phasedRegistrationName = phasedRegistrationNames [phaseName] / / populate to form registrationNameModules React synthetic events-> React handles event plug-in mapping relationship registrationNameModules [phasedRegistrationName] = pluginModule; / / populate to form registrationNameDependencies React synthetic events-> native event mapping relationship registrationNameDependencies [phasedRegistrationName] = pluginModule.eventTypes [eventName] .dependencies;}} return true;}}
The publishEventForPlugin action forms the mapping relationship in the above registrationNameModules and registrationNameDependencies objects.
3 event synthesis summary
Now that the entire initialization phase is over, let me summarize what the initialization event synthesis has done. This stage mainly forms several important objects mentioned above, constructs the corresponding relationship between initializing React synthesis events and native events, and combines events and corresponding event handling plug-ins. Next comes the event binding phase.
Three event bindings-start the event binding process with a click event
If we write a click event like this in a component, how React will handle it step by step.
1 diffProperties handles React composition events
Click
In the first step, through the above explanation, we bind the fiber of the hostComponent type (such as the button element above) to the corresponding fiber of button, and save it with memoizedProps and pendingProps.
Button corresponds to fiber memoizedProps = {onClick:function handerClick () {}, className:'button'}
The structure diagram is as follows:
58E6A4AF-1902-42BC-9D11-B47234037E01.jpg
In the second step, React enters the diff phase after reconciling the child nodes. if it is judged to be a fiber of type HostComponent (dom element), it will be processed separately with the diff props function diffProperties.
React-dom/src/client/ReactDOMComponent.jsfunction diffProperties () {/ * determine whether the current propKey is a React composite event * / if (registrationNameModules.hasOwnProperty (propKey)) {/ * the functions here are simplified. If it is a composite event, pass in the event name onClick and register the event * / legacyListenToEvent (registrationName, document) with document;}}
The diffProperties function calls the legacyListenToEvent function if it is found to be a composite event (onClick) in diff props. Register the event listener.
2 legacyListenToEvent registration event listener
React-dom/src/events/DOMLegacyEventPluginSystem.js// registrationName-> onClick event / / mountAt-> document or container function legacyListenToEvent (registrationName,mountAt) {const dependencies = registrationNameDependencies [registrationName]; / / get the array of events that onClick depends on ['click'] according to onClick. For (let I = 0; I
< dependencies.length; i++) { const dependency = dependencies[i]; //这个经过多个函数简化,如果是 click 基础事件,会走 legacyTrapBubbledEvent ,而且都是按照冒泡处理 legacyTrapBubbledEvent(dependency, mountAt); } } legacyTrapBubbledEvent 就是执行将绑定真正的dom事件的函数 legacyTrapBubbledEvent(冒泡处理)。 function legacyTrapBubbledEvent(topLevelType,element){ addTrappedEventListener(element,topLevelType,PLUGIN_EVENT_SYSTEM,false) } 第三步:在legacyListenToEvent函数中,先找到 React 合成事件对应的原生事件集合,比如 onClick ->['click'], onChange-> [blur, change, input, keydown, keyup], and then iterate through the array of dependencies, binding events, which explains why we bound only one onChange event to the element in the initial demo, and the reason why there are so many event listeners on document is handled on this function.
As we have revealed above, React uses event binding. For basic events such as click, React will handle events in the event bubbling phase by default, but this is not absolute, such as the handling of some events, and some special events are handled according to event capture.
Case TOP_SCROLL: {/ / scroll event legacyTrapCapturedEvent (TOP_SCROLL, mountAt); / / legacyTrapCapturedEvent event capture processing. Break;} case TOP_FOCUS: / / focus event case TOP_BLUR: / / blur event legacyTrapCapturedEvent (TOP_FOCUS, mountAt); legacyTrapCapturedEvent (TOP_BLUR, mountAt); break
3 bind dispatchEvent for event listening
For example, scroll events, focus events, blur events, etc., are handled according to the event capture logic by default. Next is the most important and crucial step. How does React bind events to document? What is the event handler function? The questions all point to the above addTrappedEventListener, let's unveil it.
/ * targetContainer-> document topLevelType-> click capture = false * / function addTrappedEventListener (targetContainer,topLevelType,eventSystemFlags,capture) {const listener = dispatchEvent.bind (null,topLevelType,eventSystemFlags,targetContainer) if (capture) {/ / event capture phase handler. } else {/ * TODO: important, real event binding is done here. * / targetContainer.addEventListener (topLevelType,listener,false) / / document.addEventListener ('click',listener,false)}}
Step 4: although the content of this function is not much, it is very important. First, bind our unified event handler dispatchEvent, bind several default parameters, click in the event type topLevelType demo, and bind the container doucment. Then add the event listener addEventListener to the actual event binding. The event binding phase is complete.
4. Summary of event binding process
Let's summarize the event binding phase.
When ① is in the props of fiber of React,diff DOM element type, if it is found to be a React composite event, such as onClick, it will be handled separately according to the event system logic.
② synthesizes the event type according to React, finds the corresponding native event type, and then calls to determine the native event type. Most events are handled according to bubble logic, and a few events are handled according to capture logic (such as scroll event).
③ calls addTrappedEventListener for real event binding, which is bound to document, and dispatchEvent is a unified event handler.
One thing worth noting about ④ is that only those special events mentioned above, such as scorll,focus,blur, occur in the event capture phase, and the others occur in the event bubbling phase, both onClick and onClickCapture occur in the bubbling phase, as for how React itself handles the capture logic. We'll talk about it next.
Four event triggers-one click event, what happens in the underlying react system? Click
Or the code snippet above, what happens at the bottom of the React when a button is clicked? Next, let me explore the mystery of the event.
Event trigger handler function dispatchEvent
As we said in the event binding phase, when the React event is registered, the unified listener dispatchEvent, that is, when we click the button, the first thing we execute is the dispatchEvent function. Because the first three parameters of dispatchEvent have been entered by bind, the real event source object event is bound to the fourth parameter by default.
React-dom/src/events/ReactDOMEventListener.jsfunction dispatchEvent (topLevelType,eventSystemFlags,targetContainer,nativeEvent) {/ * attempt to schedule events * / const blockedOn = attemptToDispatchEvent (topLevelType,eventSystemFlags,targetContainer,nativeEvent);}
The following are the main things done at this stage:
① first finds the real dom element of e.target based on the real event source object.
② then finds the corresponding fiber object targetInst based on the dom element, and in our demo, find the fiber corresponding to the button button.
③ then officially enters the event handling system of legacy mode, that is, the React mode we currently use is in legacy mode. In this mode, the principle of batch update is about to begin.
The question here is, how does React find the corresponding fiber through the native dom element, that is to say, what is the principle of getClosestInstanceFromNode?
The answer is that first of all, getClosestInstanceFromNode can find the fiber object of the most recent element type corresponding to the currently passed dom. When React initializes the real dom, it points to the fiber object corresponding to the current dom with a random key internalInstanceKey pointer, and the fiber object points to the current dom element with stateNode.
/ / declare random key var internalInstanceKey ='_ reactInternalInstance$' + randomKey; / / use random key function getClosestInstanceFromNode (targetNode) {/ / targetNode-dom targetInst-> corresponding fiber object var targetInst = targetNode [internalInstanceKey];}
Look at it on the Google debugger
Fiber_dom.jpg
Diagram of the relationship between the two
Dom_fiber.jpg
Legacy event handling system and batch update react-dom/src/events/DOMLegacyEventPluginSystem.js/* topLevelType-click event | eventSystemFlags = 1 | nativeEvent = event source object | fiber object * / function dispatchEventForLegacyPluginEventSystem (topLevelType,eventSystemFlags,nativeEvent,targetInst) corresponding to targetInst = element {/ * take one from the React event pool and assign topLevelType, targetInst and other attributes to the event * / const bookKeeping = getTopLevelCallbackBookKeeping (topLevelType,nativeEvent,targetInst,eventSystemFlags) Try {/ * perform batch update handleTopLevel is the main function of event handling * / batchedEventUpdates (handleTopLevel, bookKeeping);} finally {/ * release event pool * / releaseTopLevelCallbackBookKeeping (bookKeeping);}}
For the v16 event pool, we'll talk about it next. First of all, batchedEventUpdates is the main function of batch updates. Let's take a look at batchedEventUpdates.
React-dom/src/events/ReactDOMUpdateBatching.jsexport function batchedEventUpdates (fn,a) {isBatchingEventUpdates = true; try {fn (a) / / handleTopLevel (bookKeeping)} finally {isBatchingEventUpdates = false}}
Batch updates are simplified to the above, from which we can see that React controls whether batch updates are enabled or not by turning on isBatchingEventUpdates. Fn (a), the event call is handleTopLevel (bookKeeping), and because js is single-threaded, the event handlers we actually write in the component, such as demo's handerClick execution, are actually executed in handleTopLevel (bookKeeping). So if we trigger setState in handerClick, we can read isBatchingEventUpdates = true, which is why React's composite events have batch update capabilities. For example, we write like this.
State= {number:0} handerClick = () = > {this.setState ({number: this.state.number + 1}) console.log (this.state.number) / 0 this.setState ({number: this.state.number + 1}) console.log (this.state.number) / / 0 setTimeout (() = > {this.setState ({number: this.state.number + 1}) console.log (this) .state.number) / / 2 this.setState ({number: this.state.number + 1}) console.log (this.state.number) / / 3})}
As shown above, the first setState and the second setState are executed within the batch update condition, so printing will not be the latest value, but if it happens in setTimeout, because eventLoop is executed in the next event loop, isBatchingEventUpdates = false has been executed in batchedEventUpdates, so the batch update is broken and we can directly access the newly changed values.
Next, there are two points we haven't sorted out:
One is the concept of React event pool.
The second is that the last clue is to execute handleTopLevel (bookKeeping), so what exactly did handleTopLevel write?
Execute event plug-in function
It talks about the whole event system, and finally points to the function handleTopLevel (bookKeeping). So what exactly does handleTopLevel do?
/ / after the process is simplified / / topLevelType-click / / targetInst-button Fiber / / nativeEvent function handleTopLevel (bookKeeping) {const {topLevelType,targetInst,nativeEvent,eventTarget, eventSystemFlags} = bookKeeping for (let item0; I
< plugins.length;i++ ){ const possiblePlugin = plugins[i]; /* 找到对应的事件插件,形成对应的合成event,形成事件执行队列 */ const extractedEvents = possiblePlugin.extractEvents(topLevelType,targetInst,nativeEvent,eventTarget,eventSystemFlags) } if (extractedEvents) { events = accumulateInto(events, extractedEvents); } /* 执行事件处理函数 */ runEventsInBatch(events); } 我把整个流程简化,只保留了核心的流程,handleTopLevel最后的处理逻辑就是执行我们说的事件处理插件(SimpleEventPlugin)中的处理函数extractEvents,比如我们demo中的点击事件 onClick 最终走的就是 SimpleEventPlugin 中的 extractEvents 函数,那么React为什么这么做呢? 我们知道我们React是采取事件合成,事件统一绑定,并且我们写在组件中的事件处理函数( handerClick ),也不是真正的执行函数dispatchAciton,那么我们在handerClick的事件对象 event,也是React单独合成处理的,里面单独封装了比如 stopPropagation和preventDefault等方法,这样的好处是,我们不需要跨浏览器单独处理兼容问题,交给React底层统一处理。 extractEvents 形成事件对象event 和 事件处理函数队列 重点来了!重点来了!重点来了!,extractEvents 可以作为整个事件系统核心函数,我们先回到最初的demo,如果我们这么写,那么四个回调函数,那么点击按钮,四个事件是如何处理的呢。首先如果点击按钮,最终走的就是extractEvents函数,一探究竟这个函数。 legacy-events/SyntheticEvent.jsconst SimpleEventPlugin = { extractEvents:function(topLevelType,targetInst,nativeEvent,nativeEventTarget){ const dispatchConfig = topLevelEventsToDispatchConfig.get(topLevelType); if (!dispatchConfig) { return null; } switch(topLevelType){ default: EventConstructor = SyntheticEvent; break; } /* 产生事件源对象 */ const event = EventConstructor.getPooled(dispatchConfig,targetInst,nativeEvent,nativeEventTarget) const phasedRegistrationNames = event.dispatchConfig.phasedRegistrationNames; const dispatchListeners = []; const {bubbled, captured} = phasedRegistrationNames; /* onClick / onClickCapture */ const dispatchInstances = []; /* 从事件源开始逐渐向上,查找dom元素类型HostComponent对应的fiber ,收集上面的React合成事件,onClick / onClickCapture */ while (instance !== null) { const {stateNode, tag} = instance; if (tag === HostComponent && stateNode !== null) { /* DOM 元素 */ const currentTarget = stateNode; if (captured !== null) { /* 事件捕获 */ /* 在事件捕获阶段,真正的事件处理函数 */ const captureListener = getListener(instance, captured); if (captureListener != null) { /* 对应发生在事件捕获阶段的处理函数,逻辑是将执行函数unshift添加到队列的最前面 */ dispatchListeners.unshift(captureListener); dispatchInstances.unshift(instance); dispatchCurrentTargets.unshift(currentTarget); } } if (bubbled !== null) { /* 事件冒泡 */ /* 事件冒泡阶段,真正的事件处理函数,逻辑是将执行函数push到执行队列的最后面 */ const bubbleListener = getListener(instance, bubbled); if (bubbleListener != null) { dispatchListeners.push(bubbleListener); dispatchInstances.push(instance); dispatchCurrentTargets.push(currentTarget); } } } instance = instance.return; } if (dispatchListeners.length >0) {/ * queue the function execution to the event object event * / event._dispatchListeners = dispatchListeners; event._dispatchInstances = dispatchInstances; event._dispatchCurrentTargets = dispatchCurrentTargets;} return event}}
The core extractEvents of the event plug-in system mainly does:
① first forms a unique composite event source object for React events, which holds the information about the entire event. Is passed as an argument to the real event handler (handerClick).
② then declares the event execution queue, and according to the bubbling and capture logic, the artifact source begins to go up gradually, looking for the fiber corresponding to the dom element type HostComponent, collecting the above React composite events, such as onClick / onClickCapture, push to the execution queue for events in the bubbling phase (onClick), and unShift to the front of the execution queue for events in the capture phase (onClickCapture).
Finally, ③ saves the event execution queue to the React event source object. Waiting for execution.
For example, such as the following
HanderClick = () = > console.log (1) handerClick1 = () = > console.log (2) handerClick2 = () = > console.log (3) handerClick3= () = > console.log (4) render () {return click}
As we can see here, we should know the printing order of the above functions. First, we iterate through the fiber corresponding to button, first encounter onClickCapture, put handerClick1 at the front of the array, then put the handerClick corresponding to onClick at the back of the array, forming a structure of [handerClick1, handerClick], and then traverse up, encounter the corresponding fiber of div, put the handerClick3 corresponding to onClickCapture in front of the array, and put the handerClick2 corresponding to onClick at the back of the array. The resulting structure [handerClick3,handerClick1, handerClick,handerClick2], so the order of execution / / 4 2 1 3, is so simple and perfect!
FDEBA681-2E03-420B-A838-5907439837A9.jpg
Event trigger
Some students may be curious about what the event source object of React looks like. Let's take a look at SyntheticEvent in the above code as an example:
Legacy-events/SyntheticEvent.js/function SyntheticEvent (dispatchConfig,targetInst,nativeEvent,nativeEventTarget) {this.dispatchConfig = dispatchConfig; this._targetInst = targetInst; this.nativeEvent = nativeEvent; this._dispatchListeners = null; this._dispatchInstances = null; this._dispatchCurrentTargets = null; this.isPropagationStopped = () = > false; / * initialization, returned as false * /} SyntheticEvent.prototype= {stopPropagation () {this.isPropagationStopped = () = > true }, / * React is handled separately to prevent event bubbling function * / preventDefault () {}, / * React is handled separately, event capture function is prevented * /...}
Print e in handerClick:
B9180401-93FF-4EF0-A2FB-C2FA43B29550.jpg
Now that both the event execution queue and the event source object are formed, it is the last step that the event is triggered. Have you noticed that a function runEventsInBatch, all event binding functions, is triggered here. Let's take a look.
Legacy-events/EventBatching.jsfunction runEventsInBatch () {const dispatchListeners = event._dispatchListeners; const dispatchInstances = event._dispatchInstances; if (Array.isArray (dispatchListeners)) {for (let I = 0; I
< dispatchListeners.length; i++) { if (event.isPropagationStopped()) { /* 判断是否已经阻止事件冒泡 */ break; } dispatchListeners[i](event) } } /* 执行完函数,置空两字段 */ event._dispatchListeners = null; event._dispatchInstances = null; } dispatchListeners[i](event)就是执行我们的事件处理函数比如handerClick,从这里我们知道,我们在事件处理函数中,返回 false ,并不会阻止浏览器默认行为。 handerClick(){ //并不能阻止浏览器默认行为。 return false } 应该改成这样: handerClick(e){ e.preventDefault() } 另一方面React对于阻止冒泡,就是通过isPropagationStopped,判断是否已经阻止事件冒泡。如果我们在事件函数执行队列中,某一会函数中,调用e.stopPropagation(),就会赋值给isPropagationStopped=()=>True, when you execute e.isPropagationStopped (), it returns true, and then the event handler is not executed.
Other concepts-event pool handerClick = (e) = > {console.log (e.target) / / button setTimeout (() = > {console.log (e.target) / / null}, 0)
For an one-click event handler, printing e.target in the context of normal function execution points to the dom element, but printing in setTimeout is null. If this is not the React event system, the two prints should be the same, but why are the two prints different? Because React adopts the concept of an event pool, every time we use an event source object, after the event function is executed, we can release the event source object to the event pool through releaseTopLevelCallbackBookKeeping and other methods. This advantage is that every time we no longer have to create an event source object, we can take an event source object from the event pool for reuse. After the event handling function is executed, the event source will be released to the event pool to empty the attributes. This is why printing in setTimeout is null.
Event trigger summary
Let me summarize what I did during the event trigger phase:
① first updates batchUpdate in batches through a unified event handler function, dispatchEvent.
② then executes the extractEvents in the event processing plug-in to synthesize the event source object. Each time React will work on the event source, traversing the fiber of type hostComponent that is dom, to determine whether there are any current events in props, such as onClick, and finally form an event execution queue. React uses this queue to simulate the process of event capture-> event source-> event bubbling.
③ finally executes the event queue through runEventsInBatch, and if it is found to prevent bubbling, break jumps out of the loop, finally resets the event source, puts it back into the event pool, and completes the entire process.
Evnent_click.jpg
5 about the event system of react v17 version
The overall change in React v17 is not very big, but the event system has changed a lot. First of all, many of the above execution functions no longer exist in v17. Let me briefly describe the revision of the v17 event system.
1 events are uniformly bound to container, ReactDOM.render (app, container); instead of document, this benefit is beneficial to micro-front-end. Micro-front-end may have multiple applications in a front-end system. If you continue to bind all of them to document, there may be problems in multiple applications.
React_17_delegation.png
2 align native browser events
Support for native capture events is finally supported in React 17, aligning browser native standards. At the same time, onScroll events no longer bubble events. OnFocus and onBlur are synthesized using native focusin and focusout.
3 cancel event pool React 17 cancel event pool reuse, also solve the above problem of printing in setTimeout and not finding e.target.
This paper introduces the principle of React event system in detail from three aspects: event synthesis, event binding and event trigger.
After reading the above, have you mastered the principle of react events? If you want to learn more skills or want to know more about it, you are welcome to follow the industry information channel, thank you for reading!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.