この章であなたと議論したいのは、イエスReact
とノーです。生命周期
事件系统
jsxのコンパイル結果
jsx
上記でv17
コンパイル結果にも言及したので标签名
、他のタグ属性
( などclass
) や事件
(click
イベントなど) を除いて、それらはすべて_jsxRuntime.jsx
関数の第 2 パラメーターに配置されます。パフォーマンスの形でkey:value
、ここではいくつかの問題があります。
react
関数本体 (イベント ハンドラー) が何であるかをどのように知ることができますか?react
これらのイベントはどの段階で処理されますか?
最初にここでポイントを作りましょう. まず最初にReact
完全なアプリケーションの完全なライフサイクルがどのように見えるかを見てみましょう. 私たちは皆、それが2つのコンポーネントのライフサイクル機能にReact
分割され类组件
、その一部であることを知っています.ここで私は分析します. 2 つのコンポーネントを別々にコンポーネントのライフ サイクルを説明します。函数组件
发生了一些变化
React コンポーネントのライフサイクル
コンポーネント実装時の実行順序
_jsxRuntime.jsx
オブジェクトをコンパイルするときに、処理と静的型チェックjsx
を行うためです。したがって、これもライフサイクルです。コンポーネントは分離されており、このコンストラクタは段階的に実行されます.私はいくつかの調査を行いました.これはクラスコンポーネントに固有のものですか、それとも固有のものですか? 後で、これが独特であることがわかりました。この文をどのように理解するのですか?defaultProps
propType
Class
constructor
mount
constructor
class
constructor
class
- 「Re-learning ES6」という本で言及されています:
ES6
クラスの概念が に追加されました。クラスにはメソッドが必要です。constructor
クラスに明示的な定義がない場合、デフォルトで空のconstructor
メソッドが追加されます。ReactClassComponent
話すためconstructor
に必要な関数は、state
イベントを初期化してバインドすることです. もう1つのポイントは、宣言さconstructor
れた後に呼び出される必要があることですsuper
. 私たちは通常、それを受け取りとprops
受け渡しに使用します. 書かないconstructor
と動かない.props
constructor
props
super
- したがって、クラス コンポーネントの場合
constructor
は、ライフ サイクル フックと見なすことができます。
getDerivedStateFromProps
render メソッドが呼び出される前に呼び出され、最初のマウントとその後の更新で呼び出されます。オブジェクトを更新状態に戻す必要があります。何もnull
返さ更新されません。
render
呼び出されるthis.props
とthis.state
、次のいずれかのタイプを返します。
- 反応要素。通常、JSX 経由で作成されます。たとえば、 React によって
<div />
DOM ノードとしてレンダリングされ、React 要素<MyComponent />
である<div />
か<MyComponent />
。 - 配列またはフラグメント。render メソッドが複数の要素を返すことができるようにします。
- ポータル。子ノードを異なる DOM サブツリーにレンダリングすることができます。
- 文字列または数値型。これらは、DOM でテキスト ノードとしてレンダリングされます。
- ブール値または
null
. 何もレンダリングされません。(主に、 test がブール値である をtest && <Child />
返すます。)
componentDidMount()
コンポーネントがマウントされた (DOM ツリーに挿入された) 直後に呼び出されます。DOM ノードに依存する初期化はここで行う必要があります。これは、非同期リクエストの送信に適しています。
コンポーネント更新時の実行順序
getDerivedStateFromProps
=> shouldComponentUpdate()
=> render()
=> getSnapshotBeforeUpdate()
=>componentDidUpdate()
- これ
shouldComponentUpdate
は、パフォーマンス最適化のフックとも呼ばれます. その機能は、2 つの更新を比較するか、state
またはprops
それらが変更されたかどうかを比較し、現在のコンポーネントを更新するかどうかを決定することです. 比較方法については浅比较
、以前に説明したので、ここでは繰り返しません. - そして、
getSnapshotBeforeUpdate
関数は、最新のレンダリングされた出力 (DOM
ノードに送信される) の前に呼び出されます。これにより、コンポーネントは、変更前にコンポーネントDOM
から。このライフサイクル メソッドからの戻り値は、引数として に渡されますcomponentDidUpdate()
。 componentDidUpdate()
更新直後に呼び出されます。不会执行
このメソッドは最初にレンダリングされます。
コンポーネントのアンインストール時の実行順序
componentWillUnmount()
componentの直前卸载
に呼び出されます销毁
。cleanup など、このメソッドで必要なクリーンアップ操作を実行しますtimer
。取消网络请求
エラー発生時のコンポーネントの実行順序
getDerivedStateFromError
⇒componentDidCatch
この2つのフックについては、学生が自分で公式サイトに移動できます。
もちろん、上記はClassComponent
ライフサイクルの実行順序に過ぎず、新しいバージョンの ReactcomponentDidMount
ではcomponentDidUpdate
、 、 、 が削除され、componentWillUnMount
に置き換えられています。では、正確に3人を置き換えたのは誰ですか? この問題については、React のソース コード分析シリーズ (8) - 詳細なフックの原則で説明したので、ここでは繰り返しません。useEffect
useLayoutEffect
ここで、最初の質問に答えます。reactは関数の本体が何であるかをどのように認識しますか? この質問は実際には非常に良い質問です.babel
解析後はそれにjsx
注意を払うだけですが{事件名:函数名}
、各イベントを登録してバインドし、イベントによってトリガーされて、バインドされた関数の関数本体を実行する必要があります. この種の問題を説明するには、ソース コード内の特定の実装を確認する必要があります。
listenToAllSupportedEvents
Reactソースコード解析連載(2)で紹介した初期化コンポーネントの作成・更新処理.rootFiber
作成FiberRoot
が完了したらイベントを作成する必要があります.イベントを作成するためのエントリ関数は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);
allNativeEvents
ここにあるものに注意を払う必要があります。これは、イベント名を格納allNativeEvents
する構造体としてソース コードに反映されています。Set
export const allNativeEvents: Set<DOMEventName> = new Set();
listenToNativeEvent
次に何が起こったのか見てみましょう。
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,);
}
getEventPriorityForPluginSystem
質問がありますか? 内部イベントは確実に優先されることはわかっていますが、イベントReact
以外のイベントについてはどうでしょうか。心配しないでください。見ればわかります。React
React
原生事件
getEventPriorityForPluginSystem
export function getEventPriorityForPluginSystem( domEventName: DOMEventName, ): EventPriority {// 通过事件名获取优先级const priority = eventPriorities.get(domEventName);// ContinuousEvent为默认优先级 return priority === undefined ? ContinuousEvent : priority;
}
//eventPriorities
const eventPriorities = new Map();
eventPriorities
それ自体が Map 構造であり、2 つの場所で実行される操作を見つけることができます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]);}
}
これは、この 2 つの関数で優先処理が行われていることを意味するので、この 2 つの関数がどこで呼び出されているかを見ると、関数registerSimpleEvents
でこれら 2 つの関数がeventPriorities
実行され、優先順位が付けられていることがわかりました。
// packages/react-dom/src/events/DOMEventProperties.js
export function registerSimpleEvents() {// 处理离散事件优先级registerSimplePluginEventsAndSetTheirPriorities(discreteEventPairsForSimpleEventPlugin,DiscreteEvent,);// 处理用户阻塞事件优先级registerSimplePluginEventsAndSetTheirPriorities(userBlockingPairsForSimpleEventPlugin,UserBlockingEvent,);// 处理默认事件优先级registerSimplePluginEventsAndSetTheirPriorities(continuousPairsForSimpleEventPlugin,ContinuousEvent,);// 处理其他事件优先级setEventPriorities(otherDiscreteEvents, DiscreteEvent);
}
上記のコードには多くのコードがあることがわかりますPlugin
。コードは次のとおりです。
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',
];
registerSimplePluginEventsAndSetTheirPriorities
関数で、登録イベントを見つけました。registerTwoPhaseEvent
登録方法を調べてみましょう。
registerTwoPhaseEvent
export function registerTwoPhaseEvent( registrationName: string, // 注册事件reactNamedependencies: Array<DOMEventName>, // 依赖 ): void {registerDirectEvent(registrationName, dependencies);registerDirectEvent(registrationName + 'Capture', dependencies);
}
registerDirectEvent
// 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]);}
}
allNativeEvents
保存イベント名とのことで、Set
ここに追加して事件名
完了事件注册
です。まだ終わっていません.イベント登録はイベントにバインドされていると前述しましたが、ユーザーがクリックしたとき、どのようにトリガーする必要がありますか? 上記のコードでは、優先度を取得した後、各イベントは現在の優先度に従って 1 つを生成します。listenerWrapper
これlistenerWrapper
は、対応するイベント トリガー バインディング関数です。dispatchDiscreteEvent
、dispatchUserBlockingUpdate
、およびdispatchEvent
3 つの関数はすべてバインドによって実行されますが、バインドによってバインドされた関数が新しい関数を返し、すぐには実行されないことは誰もが知っています。したがって、彼のエントリが何であるかも確認する必要があります。
this
:null
argments
:domEventName
: イベント名、eventSystemFlags
: イベント タイプ タグ、targetContainer
: 対象のコンテナ。
ディスパッチイベント
それが何であれdispatchDiscreteEvent
、最後にdispatchUserBlockingUpdate
実行されるdispatchEvent
ので、彼の実装を見ることができます。
// 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();
}
React
以上でイベントシステムの解析は終わり、上記の疑問はここで簡単に解けます.イベントReact
名とイベント処理関数のペアが束縛さ创建rootFiber
れ事件注册
て. 次に、それらの実行プロセスはおおよそ次のとおりです。事件绑定
事件调度
要約する
この章では、主にmount
、 、update
、およびフェーズdestroy
のコンポーネントのライフサイクル実行シーケンスとReact
、イベント システムの登録、バインディング、スケジュール更新などについて紹介します。
やっと
HTML、CSS、JavaScript、HTTP、TCPプロトコル、ブラウザ、VUE、React、データ構造やアルゴリズムなど、「フロントエンドメーカーインタビュー集」をまとめ、合計201問のインタビュー質問をまとめ、それぞれに回答を作成質問 答えて分析します。
困っている友達、記事の最後にあるカードをクリックしてこのドキュメントを受け取り、無料で共有できます
ドキュメントの一部は次のとおりです。
記事の長さには制限があり、次のコンテンツは順次表示されません
困っている友達は、下のカードをクリックして無料で入手できます