O que quero discutir com você neste capítulo é sim React
e não .生命周期
事件系统
O resultado da compilação de jsx
Como também mencionei jsx
os v17
resultados da compilação acima, exceto 标签名
para outras tags 属性
(como class
) e 事件
(como click
eventos), todos eles são colocados no _jsxRuntime.jsx
segundo parâmetro da função. Na forma de performance key:value
, aqui teremos vários problemas.
react
Como você sabe qual é o corpo da função (manipulador de eventos)?react
Em que estágio esses eventos são tratados?
Vamos fazer um ponto aqui primeiro. Vamos primeiro dar uma olhada em como é React
o 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.jsx
compilar jsx
objetos, faremos processamento defaultProps
e propType
verificação de tipo estático. Portanto, este também é um ciclo de vida. Class
Os componentes são separados e este construtor será executado constructor
em etapas.Eu fiz algumas pesquisas.Isso é exclusivo para componentes de classe ou é exclusivo? Mais tarde, descobri que isso é único, como entender essa frase?mount
constructor
class
constructor
class
- É mencionado no livro "Re-learning ES6":
ES6
O conceito de uma classe é adicionado em , uma classe deve ter umconstructor
método, se não houver uma definição explícita na classe, umconstructor
método vazio será adicionado por padrão. ParaReactClassComponent
falarconstructor
, a função necessária é inicializarstate
e vincular eventos. O outro ponto é queconstructor
ela deve ser chamada após ser declaradasuper
. Geralmente a usamos para receber eprops
passar. Se você não escreverconstructor
, não vai funcionarprops
. Claro, se você quiserconstructor
usar emprops
, você deve usar asuper
recepção. - Portanto, para componentes de classe,
constructor
pode ser considerado um gancho de ciclo de vida.
getDerivedStateFromProps
Será 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 null
retornar nada será atualizado.
render
Quando chamado, ele verifica this.props
se this.state
há 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 ou
null
. Nada é renderizado. (Usado principalmente para suportar padrões quetest && <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çõesstate
ouprops
se 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
getSnapshotBeforeUpdate
função é chamada antes da saída renderizada mais recente (enviada aoDOM
nó). Ele permite que os componentes capturem algumas informaçõesDOM
deles . Qualquer valor de retorno desse método de ciclo de vida será passado como um argumento paracomponentDidUpdate()
. 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
=> componentDidCatch
Em relação a esses dois ganchos, os alunos podem acessar o site oficial por conta própria.
Obviamente, o acima é apenas ClassComponent
a ordem de execução do ciclo de vida e, na nova versão do React componentDidMount
, componentDidUpdate
, , , foram excluídos componentWillUnMount
e 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. babel
Após a análise, você jsx
só 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. rootFiber
Após FiberRoot
a 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 allNativeEvents
está aqui, allNativeEvents
que se reflete no código-fonte como uma Set
estrutura que armazena os nomes dos eventos:
export const allNativeEvents: Set<DOMEventName> = new Set();
Vamos ver listenToNativeEvent
o 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 getEventPriorityForPluginSystem
aqui. Você tem uma pergunta React
? Nós sabemos que os eventos internos React
com certeza serão priorizados, mas e os não React
eventos, 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 eventPriorities
executadas 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 Plugin
có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 registerSimplePluginEventsAndSetTheirPriorities
funçã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 dispatchEvent
trê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
, dispatchUserBlockingUpdate
ele 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, React
a análise do sistema de eventos está concluída e as perguntas acima podem ser facilmente respondidas aqui. React
O nome do evento e o par de funções de processamento de eventos são vinculados e, 创建rootFiber
quando 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.destroy
React
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