Ciclo de vida y sistema de eventos en el código fuente de reacción.

Lo que quiero discutir con usted en este capítulo es sí Reacty no .生命周期事件系统

El resultado de la compilación de jsx.

Debido a que también mencioné jsxlos v17resultados de la compilación anteriormente, a excepción 标签名de otras etiquetas 属性(como class) y 事件(como clickeventos), todos se colocan en _jsxRuntime.jsxel segundo parámetro de la función. En la forma de rendimiento key:value, aquí tendremos varios problemas.

  • react¿Cómo sabe cuál es el cuerpo de la función (controlador de eventos)?
  • react¿En qué etapa se manejan estos eventos?

Hagamos un punto aquí primero. Primero echemos un vistazo a cómo se ve Reactel ciclo de vida completo de una aplicación completa. Todos sabemos que se Reactdivide en 类组件y es 函数组件parte de las funciones del ciclo de vida de los dos componentes. 发生了一些变化Aquí analizaré el dos componentes por separado Explicar el ciclo de vida de los componentes.

Reaccionar ciclo de vida del componente

Orden de ejecución cuando se montan los componentes

Porque al _jsxRuntime.jsxcompilar jsxobjetos, haremos procesamiento defaultPropsy propTypeverificación de tipos estáticos. Así que esto también es un ciclo de vida. ClassLos componentes están separados y este constructor se ejecutará constructoren etapas. He investigado un poco. ¿Es esto único para los componentes de clase o es único? Más tarde, descubrí que esto es único, ¿cómo entender esta oración?mountconstructorclassconstructorclass

  • Se menciona en el libro "Re-learning ES6": ES6El concepto de una clase se agrega en , una clase debe tener un constructormétodo, si no hay una definición explícita en la clase, constructorse agregará un método vacío por defecto. Para ReactClassComponenthablar constructor, la función requerida es inicializar statey vincular eventos. El otro punto es que constructordebe llamarse después de que se declare super. Generalmente lo usamos para recibir y propspasar. Si no lo escribes constructor, no funcionará propsPor supuesto, si quieres constructorusarlo en props, debes usar superrecepción.
  • Entonces, para los componentes de clase, constructorpuede considerarse como un gancho del ciclo de vida.

getDerivedStateFromPropsSe llamará antes de que se llame al método render y se llamará en el montaje inicial y las actualizaciones posteriores. Debería devolver un objeto para actualizar el estado, si lo nulldevuelve , no se actualizará nada.

renderCuando se le llama, this.propscomprueba this.statesi hay cambios y devuelve uno de los siguientes tipos:

  • Reaccionar elementos . Por lo general, se crea a través de JSX. Por ejemplo, React <div />lo renderizará como un nodo DOM <MyComponent />, y React lo renderizará como un componente personalizado, <div />ya <MyComponent />un elemento de React.
  • matriz o fragmentos . Habilita el método render para devolver varios elementos.
  • portales _ Es posible representar nodos secundarios en diferentes subárboles DOM.
  • Tipo de cadena o numérico . Se representan como nodos de texto en el DOM.
  • booleano onull . No se renderiza nada. (Se utiliza principalmente para admitir patrones que test && <Child />devuelven , donde test es un valor booleano).

componentDidMount()Se llamará inmediatamente después de montar el componente (insertado en el árbol DOM). La inicialización que depende de los nodos DOM debe ir aquí. Esto es adecuado para enviar solicitudes asíncronas.

Orden de ejecución cuando se actualizan los componentes

getDerivedStateFromProps=> shouldComponentUpdate()=> render()=> getSnapshotBeforeUpdate()=>componentDidUpdate()

  • También shouldComponentUpdatese le llama gancho para la optimización del rendimiento. Su función es comparar las dos actualizaciones stateo propssi han cambiado y decidir si actualizar el componente actual. El método de comparación es 浅比较el que se ha mencionado anteriormente y no se repetirá aquí.
  • Y la getSnapshotBeforeUpdatefunción se llama antes de la salida renderizada más reciente (enviada al DOMnodo). Permite que los componentes capturen alguna información DOMde ellos . Cualquier valor de retorno de este método de ciclo de vida se pasará como argumento a componentDidUpdate().
  • componentDidUpdate()será llamado inmediatamente después de la actualización. 不会执行Este método se renderiza primero .

Orden de ejecución cuando se desinstalan los componentes

componentWillUnmount()卸载Se llamará directamente antes del componente 销毁. Realice las operaciones de limpieza necesarias en este método, como limpieza timer, 取消网络请求etc.

Orden de ejecución de los componentes cuando se produce un error

getDerivedStateFromError=> componentDidCatchCon respecto a estos dos ganchos, los estudiantes pueden acceder al sitio web oficial por sí mismos.

Por supuesto, lo anterior es solo ClassComponentel orden de ejecución del ciclo de vida, y en la nueva versión de React componentDidMount, componentDidUpdate, , , han sido eliminados componentWillUnMounty reemplazados por useEffect, useLayoutEffect. Entonces, ¿quién reemplazó exactamente a los tres? Ya expliqué este problema en la serie de análisis de código fuente de React (8), el principio de los ganchos en profundidad, por lo que no lo repetiré aquí.

Ahora, para responder a la primera pregunta: ¿cómo sabe react cuál es el cuerpo de la función? Esta pregunta es realmente muy buena. babelDespués del análisis, jsxsolo le prestará atención {事件名:函数名}, pero cada evento debe registrarse y vincularse, y luego activarse por el evento para ejecutar el cuerpo de la función de la función vinculada. Para explicar este tipo de problema, todavía tenemos que mirar la implementación específica en el código fuente.

listenToAllSupportedEvents

Mencionamos en la serie de análisis del código fuente de React (2) - el proceso de creación y actualización del componente de inicialización. rootFiberUna vez FiberRootcompletada la creación, necesitamos crear un evento. La función de entrada para crear un evento es listenToAllSupportedEvents.

// packages/react-dom/src/events/DOMPluginEventSystem.js
export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {if (enableEagerRootListeners) { // enableEagerRootListeners默认值为false// listeningMarker就是一个随机数+字符串,作为唯一值if (rootContainerElement[listeningMarker]) {...return;}rootContainerElement[listeningMarker] = true;// 遍历allNativeEvents的所有事件allNativeEvents.forEach(domEventName => {// 如果不是委托事件,没有冒泡阶段// nonDelegatedEvents全部媒体事件,if (!nonDelegatedEvents.has(domEventName)) {listenToNativeEvent(domEventName,false,((rootContainerElement: any): Element),null,);}// 有冒泡阶段listenToNativeEvent(domEventName,true,((rootContainerElement: any): Element),null,);});}
}

//listeningMarker
// 唯一标识
const listeningMarker ='_reactListening' +Math.random().toString(36).slice(2); 

Debemos prestar atención a lo que allNativeEventshay aquí, allNativeEventsque se refleja en el código fuente como una Setestructura que almacena nombres de eventos:

export const allNativeEvents: Set<DOMEventName> = new Set(); 

Veamos listenToNativeEventqué pasó después.

listenToNativeEvent

export function listenToNativeEvent( domEventName: DOMEventName,// 事件名isCapturePhaseListener: boolean, // 根据上个函数,这里应该是确定是是能够冒泡的事件rootContainerElement: EventTarget,targetElement: Element | null,eventSystemFlags?: EventSystemFlags = 0, // 事件标记 ): void {let target = rootContainerElement;//如果是selectionchange事件,加到dom上if (domEventName === 'selectionchange' &&(rootContainerElement: any).nodeType !== DOCUMENT_NODE) {target = (rootContainerElement: any).ownerDocument;}if (targetElement !== null &&!isCapturePhaseListener &&nonDelegatedEvents.has(domEventName) // 非冒泡事件) { ...//滚动事件不冒泡if (domEventName !== 'scroll') {return;}eventSystemFlags |= IS_NON_DELEGATED; // is_non_delegated 不是委托事件target = targetElement;}//获取dom上绑定的事件名数组 Set[] || const listenerSet = getEventListenerSet(target);// 处理事件名为捕获阶段与冒泡阶段 Set[click_bubble]const listenerSetKey = getListenerSetKey(domEventName,isCapturePhaseListener,);// 把没有打过的IS_CAPTURE_PHASE的符合条件的事件,打上标签if (!listenerSet.has(listenerSetKey)) {if (isCapturePhaseListener) {// 打上捕获的标签eventSystemFlags |= IS_CAPTURE_PHASE;}// 往节点上添加事件绑定addTrappedEventListener(target,domEventName,eventSystemFlags,isCapturePhaseListener,);// 往listenerSet中添加事件名listenerSet.add(listenerSetKey);}
}

//getEventListenerSet
export function getEventListenerSet(node: EventTarget): Set<string> {let elementListenerSet = (node: any)[internalEventHandlersKey];if (elementListenerSet === undefined) {// 创建一个Set来存放事件名elementListenerSet = (node: any)[internalEventHandlersKey] = new Set();}return elementListenerSet;
}

// getListenerSetKey
export function getListenerSetKey( domEventName: DOMEventName,capture: boolean, ): string {// capture捕获,bubble冒泡return `${domEventName}__${capture ? 'capture' : 'bubble'}`;
}

// addTrappedEventListener
function addTrappedEventListener( targetContainer: EventTarget, // 容器domEventName: DOMEventName, // 事件名eventSystemFlags: EventSystemFlags, //事件名标识isCapturePhaseListener: boolean, // 事件委托isDeferredListenerForLegacyFBSupport?: boolean, ) {// 创建具有优先级的事件监听函数,返回值为functionlet listener = createEventListenerWrapperWithPriority(targetContainer,domEventName,eventSystemFlags,);...targetContainer =enableLegacyFBSupport && isDeferredListenerForLegacyFBSupport? (targetContainer: any).ownerDocument: targetContainer;let unsubscribeListener;...// 区分捕获、冒泡 通过node.addEventListener绑定事件到节点上if (isCapturePhaseListener) {if (isPassiveListener !== undefined) {unsubscribeListener = addEventCaptureListenerWithPassiveFlag(targetContainer,domEventName,listener,isPassiveListener,);} else {unsubscribeListener = addEventCaptureListener(targetContainer,domEventName,listener,);}} else {if (isPassiveListener !== undefined) {unsubscribeListener = addEventBubbleListenerWithPassiveFlag(targetContainer,domEventName,listener,isPassiveListener,);} else {unsubscribeListener = addEventBubbleListener(targetContainer,domEventName,listener,);}}
}

// createEventListenerWrapperWithPriority
export function createEventListenerWrapperWithPriority( targetContainer: EventTarget, // 容器domEventName: DOMEventName, // 事件名eventSystemFlags: EventSystemFlags, //标识 ): Function {// 获取事件Map里面已经标记好的优先级const eventPriority = getEventPriorityForPluginSystem(domEventName);let listenerWrapper;// 根据优先级不同绑定不同的执行函数switch (eventPriority) {//离散事件case DiscreteEvent:listenerWrapper = dispatchDiscreteEvent;break;// 用户交互阻塞渲染的事件 case UserBlockingEvent:listenerWrapper = dispatchUserBlockingUpdate;break;// 其他事件case ContinuousEvent:// 默认事件default:listenerWrapper = dispatchEvent;break;}return listenerWrapper.bind(null,domEventName,eventSystemFlags,targetContainer,);
} 

Aquí nos enfocamos en obtener la prioridad getEventPriorityForPluginSystemaquí. ¿Tiene alguna pregunta React? Sabemos que los eventos internos Reactdefinitivamente tendrán prioridad, pero ¿qué pasa con los no Reacteventos, por ejemplo 原生事件, cómo se determinan sus prioridades? No te preocupes, ya veremos cuando le echemos un vistazo.

getEventPriorityForPluginSystem

export function getEventPriorityForPluginSystem( domEventName: DOMEventName, ): EventPriority {// 通过事件名获取优先级const priority = eventPriorities.get(domEventName);// ContinuousEvent为默认优先级 return priority === undefined ? ContinuousEvent : priority;
}

//eventPriorities
const eventPriorities = new Map(); 

eventPrioritiesEs una estructura Map en sí misma, y ​​podemos encontrar las operaciones realizadas en dos lugares eventPriorities.set().

// packages/react-dom/src/events/DOMEventProperties.js
function setEventPriorities( eventTypes: Array<DOMEventName>,priority: EventPriority, ): void {for (let i = 0; i < eventTypes.length; i++) {// 往eventPriorities添加优先级eventPriorities.set(eventTypes[i], priority);}
}

//registerSimplePluginEventsAndSetTheirPriorities
function registerSimplePluginEventsAndSetTheirPriorities( eventTypes: Array<DOMEventName | string>,priority: EventPriority, ): void {for (let i = 0; i < eventTypes.length; i += 2) {const topEvent = ((eventTypes[i]: any): DOMEventName);const event = ((eventTypes[i + 1]: any): string);const capitalizedEvent = event[0].toUpperCase() + event.slice(1);// 改变事件名 click => onClickconst reactName = 'on' + capitalizedEvent;// 往eventPriorities添加优先级eventPriorities.set(topEvent, priority);topLevelEventsToReactNames.set(topEvent, reactName);// 注册捕获阶段,冒泡阶段的事件registerTwoPhaseEvent(reactName, [topEvent]);}
} 

Esto significa que el procesamiento de prioridad se ha realizado en estas dos funciones, por lo que podemos ver dónde se llaman estas dos funciones. Encontramos que en la función registerSimpleEvents, estas dos funciones se eventPrioritiesejecutaron y se le agregó prioridad.

// packages/react-dom/src/events/DOMEventProperties.js
export function registerSimpleEvents() {// 处理离散事件优先级registerSimplePluginEventsAndSetTheirPriorities(discreteEventPairsForSimpleEventPlugin,DiscreteEvent,);// 处理用户阻塞事件优先级registerSimplePluginEventsAndSetTheirPriorities(userBlockingPairsForSimpleEventPlugin,UserBlockingEvent,);// 处理默认事件优先级registerSimplePluginEventsAndSetTheirPriorities(continuousPairsForSimpleEventPlugin,ContinuousEvent,);// 处理其他事件优先级setEventPriorities(otherDiscreteEvents, DiscreteEvent);
} 

Puede ver que hay muchos en el código anterior , el Plugincódigo es el siguiente:

const discreteEventPairsForSimpleEventPlugin = [('cancel': DOMEventName), 'cancel',('click': DOMEventName), 'click',('close': DOMEventName), 'close',('contextmenu': DOMEventName), 'contextMenu',('copy': DOMEventName), 'copy',('cut': DOMEventName), 'cut',('auxclick': DOMEventName), 'auxClick',('dblclick': DOMEventName), 'doubleClick', // Careful!('dragend': DOMEventName), 'dragEnd',('dragstart': DOMEventName), 'dragStart',('drop': DOMEventName), 'drop',('focusin': DOMEventName), 'focus', // Careful!('focusout': DOMEventName), 'blur', // Careful!('input': DOMEventName), 'input',('invalid': DOMEventName), 'invalid',('keydown': DOMEventName), 'keyDown',('keypress': DOMEventName), 'keyPress',('keyup': DOMEventName), 'keyUp',('mousedown': DOMEventName), 'mouseDown',('mouseup': DOMEventName), 'mouseUp',('paste': DOMEventName), 'paste',('pause': DOMEventName), 'pause',('play': DOMEventName), 'play',('pointercancel': DOMEventName), 'pointerCancel',('pointerdown': DOMEventName), 'pointerDown',('pointerup': DOMEventName), 'pointerUp',('ratechange': DOMEventName), 'rateChange',('reset': DOMEventName), 'reset',('seeked': DOMEventName), 'seeked',('submit': DOMEventName), 'submit',('touchcancel': DOMEventName), 'touchCancel',('touchend': DOMEventName), 'touchEnd',('touchstart': DOMEventName), 'touchStart',('volumechange': DOMEventName), 'volumeChange',
];

const otherDiscreteEvents: Array<DOMEventName> = ['change','selectionchange','textInput','compositionstart','compositionend','compositionupdate',
];

const userBlockingPairsForSimpleEventPlugin: Array<string | DOMEventName> = [('drag': DOMEventName), 'drag',('dragenter': DOMEventName), 'dragEnter',('dragexit': DOMEventName), 'dragExit',('dragleave': DOMEventName), 'dragLeave',('dragover': DOMEventName), 'dragOver',('mousemove': DOMEventName), 'mouseMove',('mouseout': DOMEventName), 'mouseOut',('mouseover': DOMEventName), 'mouseOver',('pointermove': DOMEventName), 'pointerMove',('pointerout': DOMEventName), 'pointerOut',('pointerover': DOMEventName), 'pointerOver',('scroll': DOMEventName), 'scroll',('toggle': DOMEventName), 'toggle',('touchmove': DOMEventName), 'touchMove',('wheel': DOMEventName), 'wheel',
];

const continuousPairsForSimpleEventPlugin: Array<string | DOMEventName> = [('abort': DOMEventName), 'abort',(ANIMATION_END: DOMEventName), 'animationEnd',(ANIMATION_ITERATION: DOMEventName), 'animationIteration',(ANIMATION_START: DOMEventName), 'animationStart',('canplay': DOMEventName), 'canPlay',('canplaythrough': DOMEventName), 'canPlayThrough',('durationchange': DOMEventName), 'durationChange',('emptied': DOMEventName), 'emptied',('encrypted': DOMEventName), 'encrypted',('ended': DOMEventName), 'ended',('error': DOMEventName), 'error',('gotpointercapture': DOMEventName), 'gotPointerCapture',('load': DOMEventName), 'load',('loadeddata': DOMEventName), 'loadedData',('loadedmetadata': DOMEventName), 'loadedMetadata',('loadstart': DOMEventName), 'loadStart',('lostpointercapture': DOMEventName), 'lostPointerCapture',('playing': DOMEventName), 'playing',('progress': DOMEventName), 'progress',('seeking': DOMEventName), 'seeking',('stalled': DOMEventName), 'stalled',('suspend': DOMEventName), 'suspend',('timeupdate': DOMEventName), 'timeUpdate',(TRANSITION_END: DOMEventName), 'transitionEnd',('waiting': DOMEventName), 'waiting',
]; 

En la registerSimplePluginEventsAndSetTheirPrioritiesfunción, encontramos el evento de registro registerTwoPhaseEvent, pasemos a averiguar cómo se registra.

registrarseEvento de dos fases

export function registerTwoPhaseEvent( registrationName: string, // 注册事件reactNamedependencies: Array<DOMEventName>, // 依赖 ): void {registerDirectEvent(registrationName, dependencies);registerDirectEvent(registrationName + 'Capture', dependencies);
} 

registrarseDirectEvent

// Mapping from registration name to event name
export const registrationNameDependencies = {};

export function registerDirectEvent( registrationName: string, //react事件名onClickdependencies: Array<DOMEventName>, // 依赖 ) {...// 以react事件名为key,dependencies为value的map对象registrationNameDependencies[registrationName] = dependencies;if (__DEV__) {...}// 遍历依赖,把每一项加入到allNativeEvents中去for (let i = 0; i < dependencies.length; i++) {allNativeEvents.add(dependencies[i]);}
} 

Se dice que allNativeEventses un nombre de evento de almacenamiento Set, agréguelo aquí 事件名y listo 事件注册. Aún no ha terminado Se mencionó anteriormente que el registro del evento está vinculado al evento, pero cuando el usuario hace clic, ¿cómo debe activarse? En el código anterior, después de obtener la prioridad, cada evento generará uno de acuerdo con la prioridad actual listenerWrapper, que listenerWrapperes la función de enlace de activación del evento correspondiente. dispatchDiscreteEvent, dispatchUserBlockingUpdatey las dispatchEventtres funciones se ejecutan a través de bind.Todos sabemos que la función enlazada por bind devolverá una nueva función y no se ejecutará de inmediato. Así que también tenemos que ver cuál es su entrada.

  • this:null
  • argments: domEventName: nombre del evento, eventSystemFlags: etiqueta de tipo de evento, targetContainer: contenedor de destino.

DispatchEvent

Porque sea lo que sea dispatchDiscreteEvent, dispatchUserBlockingUpdatese ejecutará al final dispatchEvent, por lo que podemos echar un vistazo a su implementación.

// packages/react-dom/src/events/ReactDOMEventListener.js
export function dispatchEvent( domEventName: DOMEventName, // 事件名eventSystemFlags: EventSystemFlags, // 事件类型标记targetContainer: EventTarget, // 目标容器nativeEvent: AnyNativeEvent, // native事件 ): void {...// 如果被阻塞了,尝试调度事件 并返回挂载的实例或者容器const blockedOn = attemptToDispatchEvent(domEventName,eventSystemFlags,targetContainer,nativeEvent,);if (blockedOn === null) {// We successfully dispatched this event....return;}...// 调度事件,触发事件dispatchEventForPluginEventSystem(domEventName,eventSystemFlags,nativeEvent,null,targetContainer,);
}

// dispatchEventForPluginEventSystem
export function dispatchEventForPluginEventSystem( domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,nativeEvent: AnyNativeEvent,targetInst: null | Fiber,targetContainer: EventTarget, ): void {...//批量更新事件 batchedEventUpdates(() =>dispatchEventsForPlugins(domEventName,eventSystemFlags,nativeEvent,ancestorInst,targetContainer,),);
}

// batchedEventUpdates
export function batchedEventUpdates(fn, a, b) {...isBatchingEventUpdates = true;try {// fn : ()=>dispatchEventsForPlugins//(domEventName,eventSystemFlags,ativeEvent,ancestorInst,targetContainer,),// a: undefined// b: undefinedreturn batchedEventUpdatesImpl(fn, a, b); // batchedEventUpdatesImpl(fn, a, b) =>// Defaults// let batchedUpdatesImpl = function(fn, bookkeeping) {// return fn(bookkeeping); 执行dispatchEventsForPlugins
};} finally {...}
} 

DispatchEventsForPlugins

function dispatchEventsForPlugins( domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,nativeEvent: AnyNativeEvent,targetInst: null | Fiber,targetContainer: EventTarget, ): void {const nativeEventTarget = getEventTarget(nativeEvent);const dispatchQueue: DispatchQueue = [];//创建合成事件,遍历fiber链表,将会触发的事件加入到dispatchQueue中extractEvents(dispatchQueue,domEventName,targetInst,nativeEvent,nativeEventTarget,eventSystemFlags,targetContainer,);//触发时间队列,执行事件processDispatchQueue(dispatchQueue, eventSystemFlags);
}

//extractEvents
function extractEvents( dispatchQueue: DispatchQueue,domEventName: DOMEventName,targetInst: null | Fiber,nativeEvent: AnyNativeEvent,nativeEventTarget: null | EventTarget,eventSystemFlags: EventSystemFlags,targetContainer: EventTarget, ) {...let from;let to;...const leave = new SyntheticEventCtor(leaveEventType,eventTypePrefix + 'leave',from,nativeEvent,nativeEventTarget,);leave.target = fromNode;leave.relatedTarget = toNode;let enter: KnownReactSyntheticEvent | null = null;...accumulateEnterLeaveTwoPhaseListeners(dispatchQueue, leave, enter, from, to);
}

//accumulateEnterLeaveTwoPhaseListeners
export function accumulateEnterLeaveTwoPhaseListeners( dispatchQueue: DispatchQueue,leaveEvent: KnownReactSyntheticEvent,enterEvent: null | KnownReactSyntheticEvent,from: Fiber | null,to: Fiber | null, ): void {const common = from && to ? getLowestCommonAncestor(from, to) : null;if (from !== null) {accumulateEnterLeaveListenersForEvent(dispatchQueue,leaveEvent,from,common,false,);}if (to !== null && enterEvent !== null) {accumulateEnterLeaveListenersForEvent(dispatchQueue,enterEvent,to,common,true,);}
}

// accumulateEnterLeaveListenersForEvent
function accumulateEnterLeaveListenersForEvent( dispatchQueue: DispatchQueue,event: KnownReactSyntheticEvent,target: Fiber,common: Fiber | null,inCapturePhase: boolean, ): void {// 获取注册的事件名const registrationName = event._reactName;// 事件处理函数容器const listeners: Array<DispatchListener> = [];//节点实例let instance = target;// 遍历fiber,获取fiber上的事件对应的事件处理函数while (instance !== null) {if (instance === common) {break;}const {alternate, stateNode, tag} = instance;if (alternate !== null && alternate === common) {break;}if (tag === HostComponent && stateNode !== null) {const currentTarget = stateNode;// 根据捕获阶段,还是冒泡阶段处理不同的函数逻辑if (inCapturePhase) {const captureListener = getListener(instance, registrationName);if (captureListener != null) {// 加入到listeners中// instance:当前fiebr实例// currentTarget:当前domlisteners.unshift(createDispatchListener(instance, captureListener, currentTarget),);}} else if (!inCapturePhase) {// 冒泡const bubbleListener = getListener(instance, registrationName);if (bubbleListener != null) {// 加入到listeners中listeners.push(createDispatchListener(instance, bubbleListener, currentTarget),);}}}// 当前fiber实例的父级instance = instance.return;}if (listeners.length !== 0) {// 把事件、事件处理函数全部推到dispatchQueue中dispatchQueue.push({event, listeners});}
}
// processDispatchQueue
export function processDispatchQueue( dispatchQueue: DispatchQueue, // 事件队列eventSystemFlags: EventSystemFlags, // 事件类型标记 ): void {const inCapturePhase = (eventSystemFlags & IS_CAPTURE_PHASE) !== 0;for (let i = 0; i < dispatchQueue.length; i++) {const {event, listeners} = dispatchQueue[i];// 执行事件,完成触发processDispatchQueueItemsInOrder(event, listeners, inCapturePhase);//event system doesn't use pooling.}// This would be a good time to rethrow if any of the event handlers threw.rethrowCaughtError();
} 

Entonces, en este punto, Reactel análisis del sistema de eventos ha terminado, y las preguntas anteriores se pueden responder fácilmente aquí. ReactEl nombre del evento y el par de funciones de procesamiento de eventos están vinculados, y 创建rootFibercuando se hace 事件注册, 事件绑定, 事件调度. Entonces su proceso de ejecución es más o menos como sigue:

Resumir

Este capítulo presenta principalmente la secuencia de ejecución del ciclo de vida de los componentes en las fases mount, updatey , y el registro, vinculación, actualización de programación, etc. del sistema de eventos.destroyReact

Por fin

Organicé un conjunto de "Colección de entrevistas de fabricantes de front-end", que incluye HTML, CSS, JavaScript, HTTP, protocolo TCP, navegador, VUE, React, estructura de datos y algoritmos, un total de 201 preguntas de entrevistas, e hice una respuesta para cada pregunta Responde y analiza.

Amigos necesitados, pueden hacer clic en la tarjeta al final del artículo para recibir este documento y compartirlo gratis

Parte de la documentación muestra:



La longitud del artículo es limitada y el siguiente contenido no se mostrará uno por uno.

Amigos que lo necesitan, pueden hacer clic en la tarjeta a continuación para obtenerla gratis

Supongo que te gusta

Origin blog.csdn.net/web22050702/article/details/128653976
Recomendado
Clasificación