• 【保姆级】react17 事件机制源码解析


    写在前面

    react17是一个过渡版本,最大的改动莫过于针对_事件机制的重构_。虽然现在react18版本已经发布了,但对事件机制这部分几乎是没有改动的,因此这里依然可以对17版本的这部分源码作一次解读。

    摘自_react_官网的独白:

    这里把个人觉得较重大的改动框出来了:

    1.将事件委托给根节点而不是document;
    2.让所有的Capture事件与浏览器捕获阶段保持一致;
    3.移除事件池;

    恕我直言,你看到的不一定是真实的

    1.元素上的事件并不是绑定在本身;2.event 并不是元素本身的事件对象;3.整个事件流(捕获、冒泡)过程都是 react 模拟的;接下来先整个面试题开开胃吧,在 react16.x 版本中,如下代码执行,弹窗组件表现如何?

    state={visible:false
    }
    componentDidMount(){document.addEventListener('click',()=>{this.setState({visible:false})})
    }
    handleClick = ()=>{this.setState({visible:true})
    }
    render(){return(<>{this.state.visible && })
    } 
    

    先卖个关子,看完后面内容就自然知道了😁。

    正式开始吧

    事件绑定
    // packages/react-dom/src/client/ReactDOMRoot.js
    function createRootImpl( container: Container, // 项目根节点tag: RootTag,options: void | RootOptions, ) {if (enableEagerRootListeners) {const rootContainerElement =container.nodeType === COMMENT_NODE ? container.parentNode : container;// 注意此函数 监听所有支持的事件listenToAllSupportedEvents(rootContainerElement);}return root;
    } 
    
    // packages/react-dom/src/events/DOMPluginEventSystem.js
    export function listenToAllSupportedEvents(rootContainerElement: EventTarget) {if (enableEagerRootListeners) {// allNativeEvents 这个变量是所有原生事件的集合allNativeEvents.forEach(domEventName => {if (!nonDelegatedEvents.has(domEventName)) {listenToNativeEvent(domEventName,false,((rootContainerElement: any): Element),null,);}listenToNativeEvent(domEventName,true,((rootContainerElement: any): Element),null,);});}
    } 
    

    这里有一个疑问 allNativeEvents 这个变量是怎么赋值的?实际上 packages/react-dom/src/events/DOMPluginEventSystem.js 在这个文件的顶部

    // packages/react-dom/src/events/DOMPluginEventSystem.js
    import * as BeforeInputEventPlugin from './plugins/BeforeInputEventPlugin';
    import * as ChangeEventPlugin from './plugins/ChangeEventPlugin';
    import * as EnterLeaveEventPlugin from './plugins/EnterLeaveEventPlugin';
    import * as SelectEventPlugin from './plugins/SelectEventPlugin';
    import * as SimpleEventPlugin from './plugins/SimpleEventPlugin';
    
    SimpleEventPlugin.registerEvents();
    EnterLeaveEventPlugin.registerEvents();
    ChangeEventPlugin.registerEvents();
    SelectEventPlugin.registerEvents();
    BeforeInputEventPlugin.registerEvents(); 
    

    在引入插件的同时调用了插件对应的事件注册方法,关于插件的内容在后续讲解针对事件源event的处理时再来讨论。

    // packages/react-dom/src/events/EventRegistry.js
    export const allNativeEvents: Set = new Set();
    export function registerDirectEvent( registrationName: string,dependencies: Array, ) {for (let i = 0; i < dependencies.length; i++) {allNativeEvents.add(dependencies[i]);}
    } 
    

    在搞清楚 allNativeEvents 的来源后我们继续往下

    // packages/react-dom/src/events/DOMPluginEventSystem.js
    function addTrappedEventListener(targetContainer: EventTarget,domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,isCapturePhaseListener: boolean,isDeferredListenerForLegacyFBSupport?: boolean,
    ) {
    // 特别注意这个地方 对事件的回调函数作了一次包装 稍后在事件触发阶段再来详细聊聊let listener = createEventListenerWrapperWithPriority(targetContainer,domEventName,eventSystemFlags,);let unsubscribeListener;if (isCapturePhaseListener) {unsubscribeListener = addEventCaptureListener(targetContainer,domEventName,listener,);} else {unsu
  • 相关阅读:
    计算机网络(第一章 概述)
    PCL——Filter
    【白帽子讲Web安全】第一章 我的安全世界观
    羡慕 Excel 的高级选择与文本框颜色呈现?Pandas 也可以拥有!! ⛵
    集合源码解析:LinkedList 精讲
    Flink学习(九)-jar 包提交给 flink 集群执行
    前端使用 Konva 实现可视化设计器(7)- 导入导出、上一步、下一步
    Deepin系统navicat15安装
    JDBC介绍
    边端融合系统安全风险分析及评估方法
  • 原文地址:https://blog.csdn.net/pfourfire/article/details/126951529