_版本:v18.2.0
本文为我花了大半年的时间潜心研究所写,转载请注明出处,谢谢
react是如何实现事件代理的
createRoot函数
** 用户在index.tsx中执行ReactDOM.createRoot创建root节点
1. 通过创建FiberRootNode实例,得到root根节点
2. 执行createFiber(HostRoot, null, null, ConcurrentMode),创建root根节点对应的fiber节点
3. root.current = fiber
4. fiber.stateNode = root
5. container[internalContainerInstanceKey] = root.current 将fiber绑定到dom容器上
6. 执行listenToAllSupportedEvents函数
1. 遍历allNativeEvents数组,此数组包含所有js事件名
判断事件名是否在nonDelegatedEvents中,其中nonDelegatedEvents数组保存着不需要冒泡的事件名
** 如果在,表示此事件只需要绑定“捕获”
执行listenToNativeEvent(domEventName, true, rootContainerElement)在rootContainerElement监听代理事件
** 如果不在,表示此事件“冒泡”和“捕获”都要执行
listenToNativeEvent(domEventName, false, rootContainerElement)
listenToNativeEvent(domEventName, true, rootContainerElement)
2. selectionchange事件单独处理,需要代理到document上
listenToNativeEvent('selectionchange', false, document)
7. 创建ReactDOMRoot实例,ReactDOMRoot构造函数的原型上绑定了render和unmount函数,返回此实例
通用函数
listenToNativeEvent函数
1. 捕获阶段:eventSystemFlags |= IS_CAPTURE_PHASE
2. 冒泡阶段:eventSystemFlags = 0
3. 执行addTrappedEventListener函数添加事件监听器
1. 调用createEventListenerWrapperWithPriority函数获取listenerWrapper
2. 如果浏览器支持事件passive,则touchstart | touchmove | wheel 事件,开启passive
3. 如果是捕获事件,开启capture
4. container.addEventListener(domEventName, listenerWrapper, {...})
createEventListenerWrapperWithPriority函数
1. 调用getEventPriority函数,根据事件名获取事件的优先级
2. 根据事件优先级获取对应的listenerWrapper
DiscreteEventPriority -> dispatchDiscreteEvent
ContinuousEventPriority -> dispatchContinuousEvent
其他 -> dispatchEvent
3. listenerWrapper.bind(null, domEventName, eventSystemFlags, targetContainer)
getEventPriority函数
根据事件名获取事件的优先级,有如下优先级
** ['cancel', 'click', 'close', 'contextmenu', 'copy', 'cut', 'auxclick', 'dblclick', 'dragend', 'dragstart', 'drop',
'focusin', 'focusout', 'input', 'invalid', 'keydown', 'keypress', 'keyup', 'mousedown', 'mouseup', 'paste', 'pause',
'play', 'pointercancel', 'pointerdown', 'pointerup', 'ratechange', 'reset', 'resize', 'seeked', 'submit',
'touchcancel', 'touchend', 'touchstart', 'volumechange', 'change', 'selectionchange', 'textInput', 'compositionstart',
'compositionend', 'compositionupdate', 'beforeblur', 'afterblur', 'beforeinput', 'blur', 'fullscreenchange', 'focus',
'hashchange', 'popstate', 'select', 'selectstart'] 返回 DiscreteEventPriority
** ['drag', 'dragenter', 'dragexit', 'dragleave', 'dragover', 'mousemove', 'mouseout', 'mouseover', 'pointermove',
'pointerout', 'pointerover', 'scroll', 'toggle', 'touchmove', 'wheel', 'mouseenter', 'mouseleave', 'pointerenter',
'pointerleave'] 返回 ContinuousEventPriority
** 其他事件,返回DefaultEventPriority
特殊情况,message事件需要根据Scheduler调度包中的currentPriorityLevel优先级,返回对应的事件优先级
附录
root = {
"tag": 1, // 指定react运行模式 ConcurrentRoot || LegacyRoot
"containerInfo": {}, // react实例挂载容器
"pendingChildren": null,
"current": null,
"pingCache": null,
"finishedWork": null,
"timeoutHandle": -1,
"context": null,
"pendingContext": null,
"callbackNode": null,
"callbackPriority": 0, // NoLane
"eventTimes": [ 0, ... ],
"expirationTimes": [ -1, ... ],
"pendingLanes": 0, // NoLanes
"suspendedLanes": 0, // NoLanes
"pingedLanes": 0, // NoLanes
"expiredLanes": 0, // NoLanes
"mutableReadLanes": 0, // NoLanes
"finishedLanes": 0, // NoLanes
"entangledLanes": 0, // NoLanes
"entanglements": [ 0, ... ],
"identifierPrefix": "", // createRoot的options参数
"onRecoverableError": reportError, // createRoot的options参数
"pooledCache": null,
"pooledCacheLanes": 0, // NoLanes
"mutableSourceEagerHydrationData": null,
"effectDuration": 0,
"passiveEffectDuration": 0,
"pendingUpdatersLaneMap": [new Set(), ...]
"_debugRootType": "createRoot()" // 创建此节点的调用方式
}
fiber = {
"tag": tag, // 节点类型
"key": key,
"elementType": null,
"type": null,
"stateNode": null,
"return": null,
"child": null,
"sibling": null,
"index": 0,
"ref": null,
"pendingProps": pendingProps,
"memoizedProps": null,
"updateQueue": null,
"memoizedState": null,
"dependencies": null,
"mode": mode,
"flags": NoFlags,
"subtreeFlags": NoFlags,
"deletions": null,
"lanes": NoLanes,
"childLanes": NoLanes,
"alternate": null,
"actualDuration": 0,
"actualStartTime": -1,
"selfBaseDuration": 0,
"treeBaseDuration": 0,
_debugHookTypes: null,
_debugNeedsRemount: false,
_debugOwner: null,
_debugSource: null,
}
allNativeEvents = [
'abort', 'auxclick', 'cancel', 'canplay', 'canplaythrough', 'click', 'close', 'contextmenu', 'copy', 'cut', 'drag',
'dragend', 'dragenter', 'dragexit', 'dragleave', 'dragover', 'dragstart', 'drop', 'durationchange', 'emptied',
'encrypted', 'ended', 'error', 'gotpointercapture', 'input', 'invalid', 'keydown', 'keypress', 'keyup', 'load',
'loadeddata', 'loadedmetadata', 'loadstart', 'lostpointercapture', 'mousedown', 'mousemove', 'mouseout', 'mouseover',
'mouseup', 'paste', 'pause', 'play', 'playing', 'pointercancel', 'pointerdown', 'pointermove', 'pointerout',
'pointerover', 'pointerup', 'progress', 'ratechange', 'reset', 'resize', 'seeked', 'seeking', 'stalled', 'submit',
'suspend', 'timeupdate', 'touchcancel', 'touchend', 'touchstart', 'volumechange', 'scroll', 'toggle', 'touchmove',
'waiting', 'wheel', 'animationend', 'animationiteration', 'animationstart', 'dblclick', 'focusin', 'focusout',
'transitionend', 'change', 'selectionchange', 'compositionend', 'textInput', 'compositionstart', 'compositionupdate']
nonDelegatedEvents = ['cancel', 'close', 'invalid', 'load', 'scroll', 'toggle', 'abort', 'canplay', 'canplaythrough',
'durationchange', 'emptied', 'encrypted', 'ended', 'error', 'loadeddata', 'loadedmetadata', 'loadstart', 'pause', 'play',
'playing', 'progress', 'ratechange', 'resize', 'seeked', 'seeking', 'stalled', 'suspend', 'timeupdate', 'volumechange', 'waiting']
标签:NoLanes,优先级,函数,代理,react,事件,null,root
From: https://www.cnblogs.com/ye-hcj/p/16823195.html