Ciclo de vida e sistema de eventos no código-fonte react

O que quero discutir com você neste capítulo é sim Reacte não .生命周期事件系统

O resultado da compilação de jsx

Como também mencionei jsxos v17resultados da compilação acima, exceto 标签名para outras tags 属性(como class) e 事件(como clickeventos), todos eles são colocados no _jsxRuntime.jsxsegundo parâmetro da função. Na forma de performance key:value, aqui teremos vários problemas.

  • reactComo você sabe qual é o corpo da função (manipulador de eventos)?
  • reactEm que estágio esses eventos são tratados?

Vamos fazer um ponto aqui primeiro. Vamos primeiro dar uma olhada em como é Reacto ciclo de vida completo de um aplicativo completo. Todos nós sabemos que ele Reacté dividido 类组件e 函数组件faz parte das funções do ciclo de vida dos dois componentes. 发生了一些变化Aqui vou analisar o dois componentes separadamente. Explique o ciclo de vida dos componentes.

Ciclo de vida do componente React

Ordem de execução quando os componentes são montados

Porque ao _jsxRuntime.jsxcompilar jsxobjetos, faremos processamento defaultPropse propTypeverificação de tipo estático. Portanto, este também é um ciclo de vida. ClassOs componentes são separados e este construtor será executado constructorem etapas.Eu fiz algumas pesquisas.Isso é exclusivo para componentes de classe ou é exclusivo? Mais tarde, descobri que isso é único, como entender essa frase?mountconstructorclassconstructorclass

  • É mencionado no livro "Re-learning ES6": ES6O conceito de uma classe é adicionado em , uma classe deve ter um constructormétodo, se não houver uma definição explícita na classe, um constructormétodo vazio será adicionado por padrão. Para ReactClassComponentfalar constructor, a função necessária é inicializar statee vincular eventos. O outro ponto é que constructorela deve ser chamada após ser declarada super. Geralmente a usamos para receber e propspassar. Se você não escrever constructor, não vai funcionar props. Claro, se você quiser constructorusar em props, você deve usar a superrecepção.
  • Portanto, para componentes de classe, constructorpode ser considerado um gancho de ciclo de vida.

getDerivedStateFromPropsSerá chamado antes do método render ser chamado e será chamado na montagem inicial e nas atualizações subsequentes. Deve retornar um objeto para atualizar o estado, se nullretornar nada será atualizado.

renderQuando chamado, ele verifica this.propsse this.statehá alterações e retorna um dos seguintes tipos:

  • Elementos de reação . Geralmente criado via JSX. Por exemplo, <div />ele será renderizado como um nó DOM <MyComponent />pelo React e será renderizado como um componente personalizado pelo React, seja ele <div />ou <MyComponent />um elemento React.
  • matriz ou fragmentos . Permite que o método render retorne vários elementos.
  • Portais . É possível renderizar nós filhos em diferentes subárvores DOM.
  • String ou tipo numérico . Eles são renderizados como nós de texto no DOM.
  • Booleano ounull . Nada é renderizado. (Usado principalmente para suportar padrões que test && <Child />retornam , onde test é um booleano.)

componentDidMount()Será chamado imediatamente após a montagem do componente (inserido na árvore DOM). Inicialização que depende de nós DOM deve ir aqui. Isso é adequado para enviar solicitações assíncronas.

Ordem de execução quando os componentes são atualizados

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

  • Também shouldComponentUpdateé chamado de gancho para otimização de desempenho. Sua função é comparar as duas atualizações stateou propsse elas foram alteradas e decidir se deve atualizar o componente atual. O método de comparação é 浅比较o que foi mencionado anteriormente e não será repetido aqui.
  • E a getSnapshotBeforeUpdatefunção é chamada antes da saída renderizada mais recente (enviada ao DOMnó). Ele permite que os componentes capturem algumas informações DOMdeles . Qualquer valor de retorno desse método de ciclo de vida será passado como um argumento para componentDidUpdate().
  • componentDidUpdate()será chamado imediatamente após a atualização. 不会执行Este método é primeiro renderizado .

Ordem de execução quando os componentes são desinstalados

componentWillUnmount()卸载Será chamado diretamente antes do componente 销毁. Execute as operações de limpeza necessárias neste método, como limpeza timer, 取消网络请求etc.

Ordem de execução do componente quando ocorre um erro

getDerivedStateFromError=> componentDidCatchEm relação a esses dois ganchos, os alunos podem acessar o site oficial por conta própria.

Obviamente, o acima é apenas ClassComponenta ordem de execução do ciclo de vida e, na nova versão do React componentDidMount, componentDidUpdate, , , foram excluídos componentWillUnMounte substituídos por useEffect, useLayoutEffect. Então, quem exatamente substituiu os três? Eu já expliquei esse problema na série de análise de código-fonte do React (8) - o princípio dos ganchos detalhados, então não vou repeti-lo aqui.

Agora, para responder à primeira pergunta: como react sabe qual é o corpo da função? Esta pergunta é realmente muito boa. babelApós a análise, você jsxsó prestará atenção a {事件名:函数名}ela, mas cada evento precisa ser registrado e vinculado e, em seguida, acionado pelo evento para executar o corpo da função da função vinculada. Para explicar esse tipo de problema, ainda temos que olhar para a implementação específica no código-fonte.

listenToAllSupportedEvents

Mencionamos na série de análise de código-fonte do React (2) - o processo de criação e atualização do componente de inicialização. rootFiberApós FiberRoota conclusão da criação, precisamos criar um evento. A função de entrada para criar um evento é 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); 

Devemos prestar atenção ao que allNativeEventsestá aqui, allNativeEventsque se reflete no código-fonte como uma Setestrutura que armazena os nomes dos eventos:

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

Vamos ver listenToNativeEvento que aconteceu a seguir.

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,);
} 

Aqui nós focamos em obter a prioridade getEventPriorityForPluginSystemaqui. Você tem uma pergunta React? Nós sabemos que os eventos internos Reactcom certeza serão priorizados, mas e os não Reacteventos, por exemplo 原生事件, como são determinadas suas prioridades? Não se preocupe, veremos quando dermos uma olhada.

getEventPriorityForPluginSystem

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

//eventPriorities
const eventPriorities = new Map(); 

eventPrioritiesÉ uma estrutura de Mapa em si, e podemos encontrar as operações realizadas em dois 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]);}
} 

Isso significa que o processamento de prioridade foi feito nessas duas funções, então podemos ver onde essas duas funções são chamadas. Descobrimos que na função registerSimpleEvents, essas duas funções foram eventPrioritiesexecutadas e adicionamos prioridade a ela.

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

Você pode ver que existem muitos no código acima , o Plugincódigo é o seguinte:

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',
]; 

Na registerSimplePluginEventsAndSetTheirPrioritiesfunção, encontramos o evento de registro registerTwoPhaseEvent, vamos descobrir como ele é registrado.

registerTwoPhaseEvent

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

registrar evento direto

// 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]);}
} 

Diz -se que allNativeEventsé um nome de evento de armazenamento Set, adicione-o aqui 事件名e pronto 事件注册. Ainda não acabou. Foi mencionado acima que o registro do evento está vinculado ao evento, mas quando o usuário clicar, como deve ser acionado? No código acima, após obter a prioridade, cada evento gerará um de acordo com a prioridade atual listenerWrapper, que listenerWrapperé a função de vinculação do acionador do evento correspondente. dispatchDiscreteEvent, dispatchUserBlockingUpdate, e as dispatchEventtrês funções são todas executadas por meio de bind. Todos sabemos que a função vinculada por bind retornará uma nova função e não será executada imediatamente. Portanto, também temos que ver qual é a entrada dele.

  • this:null
  • argments: domEventName: nome do evento, eventSystemFlags: tag do tipo de evento, targetContainer: contêiner de destino.

dispatchEvent

Porque não importa o que seja dispatchDiscreteEvent, dispatchUserBlockingUpdateele será executado no final dispatchEvent, então podemos dar uma olhada na implementação dele.

// 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();
} 

Portanto, neste ponto, Reacta análise do sistema de eventos está concluída e as perguntas acima podem ser facilmente respondidas aqui. ReactO nome do evento e o par de funções de processamento de eventos são vinculados e, 创建rootFiberquando isso é feito 事件注册, 事件绑定, , 事件调度. Então, seu processo de execução é aproximadamente o seguinte:

Resumir

Este capítulo apresenta principalmente a sequência de execução do ciclo de vida dos componentes nas fases mount, update, e e o registro, vinculação, atualização do agendamento, etc. do sistema de eventos.destroyReact

Finalmente

Organizou um conjunto de "Coleção de entrevistas de fabricantes de front-end", incluindo HTML, CSS, JavaScript, HTTP, protocolo TCP, navegador, VUE, React, estrutura de dados e algoritmo, um total de 201 perguntas de entrevista e deu uma resposta para cada pergunta Responda e analise.

Amigos necessitados, você pode clicar no cartão no final do artigo para receber este documento e compartilhá-lo gratuitamente

Parte da documentação mostra:



A extensão do artigo é limitada e o conteúdo a seguir não será exibido um por um

Amigos necessitados, você pode clicar no cartão abaixo para obtê-lo gratuitamente

Acho que você gosta

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