react 合成事件

201 阅读2分钟

动机

React 根据W3C 规范来定义自己的事件系统,其事件被称之为合成事件 (SyntheticEvent)。而其自定义事件系统的动机主要包含以下几个方面:

(1)抹平不同浏览器之间的兼容性差异。最主要的动机。

(2)事件"合成",即事件自定义。事件合成既可以处理兼容性问题,也可以用来自定义事件(例如 React 的 onChange 事件)。

(3)提供一个抽象跨平台事件机制。类似 VirtualDOM 抽象了跨平台的渲染方式,合成事件(SyntheticEvent)提供一个抽象的跨平台事件机制。

(4)可以做更多优化。例如利用事件委托机制,几乎所有事件的触发都代理到了 document,而不是 DOM 节点本身,简化了 DOM 事件处理逻辑,减少了内存开销。(React 自身模拟了一套事件冒泡的机制)

(5)可以干预事件的分发。V16引入 Fiber 架构,React 可以通过干预事件的分发以优化用户的交互体验。

具体实现分成两个阶段:

  1. 事件注册:document/容器dom 上注册、存储事件回调,在组件挂载阶段进行事件注册并存储。

  2. 事件触发:React 的事件触发只会发生在 DOM 事件流的冒泡阶段,因为在 document 上注册时就默认是在冒泡阶段被触发执行。 其大致流程如下:

  3. 触发事件,开始 DOM 事件流,先后经过三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段

  4. 当事件冒泡到 document 时,触发统一的事件分发函数 ReactEventListener.dispatchEvent

  5. 根据原生事件对象(nativeEvent)找到当前节点(即事件触发节点)对应的 ReactDOMComponent 对象

  6. 事件的合成

  • 根据当前事件类型生成对应的合成对象
  • 封装原生事件对象和冒泡机制
  • 查找当前元素以及它所有父级
  • 在 listenerBank 中查找事件回调函数并合成到 events 中
  1. 批量执行合成事件(events)内的回调函数
  2. 如果没有阻止冒泡,会将继续进行 DOM 事件流的冒泡(从 document 到 window),否则结束事件触发

React 合成事件和原生 DOM 事件的主要区别:

(1)React 组件上声明的事件没有绑定在 React 组件对应的原生 DOM 节点上。

(2)React 利用事件委托机制,将几乎所有事件的触发代理(delegate)在 document 节点上,事件对象(event)是合成对象(SyntheticEvent),不是原生事件对象,但通过 nativeEvent 属性访问原生事件对象。

(3)由于 React 的事件委托机制,React 组件对应的原生 DOM 节点上的事件触发时机总是在 React 组件上的事件之前。