React 合成事件
React的事件系统
一图流
Tip : React16及其之前的版本,React17以后已经删除
事件池
仅转载,图片来源:《「react进阶」一文吃透react事件系统原理》
Fiber
Fiber在React16之后引入,其本质是虚拟DOM的改良,用于解决递归同步虚拟DOM阻塞所导致的性能问题.在后续的事件流程中,React通过事件源对象访问DOM从而获取DOM对应的Fiber节点,收集该节点路径上的同类事件从而模拟事件的冒泡和捕获。
React合成事件
首先需要明确的是,React中我们所编写的类似下面的事件函数并非真正地绑定在div的DOM上,而是绑定在根节点root上。(React16及其之前的版本是将事件绑定在document上)
<div onClick={()=>{console.log('测试')}}>测试</div>
同时还有一点需要注意,我们所写的类似onClick等事件也不是所谓的原生事件,而是通过原生事件合成的React事件。类似click合成onClick,blur、change、input、keydown、keyUp合成为onChange
React额外处理的原因
在讲述React如何处理事件系统前,我们还是需要了解一下为什么React要做这样的事件。
-
抹平不同浏览器之间的差异,不同浏览器之间的事件机制并不相同。而
React自己根据W3C规范去实现一套适合React机制的事件系统。可以大大减少开发者在浏览器差异上栽跟头。 -
将所有事件委托至根节点
Root或者document上,可以减少事件监听的数量,优化内存开销。
事件注册
<div onClick={()=>{console.log('测试')}}>测试</div>
这个div节点最终要对应一个fiber节点,onClick则作为它的prop。当这个fiber节点进入render阶段的complete阶段时,名称为onClick的prop会被识别为事件进行处理。
当绑定事件到root上时,root上的事件监听函数是listener,listener并不是我们所写的事件处理函数,而是一个事件监听包装器,用于分化事件处理优先级。
事件触发 (事件监听器listener)
listener做的事情可以用一句话概括,负责以不同的优先级权重来触发真正的事件流程,并传递事件执行阶段标志(eventSystemFlags)---区分冒泡和捕获执行。
比如一个元素绑定了onClick事件,那么点击它的时候,绑定在root上的listener会被触发,会最终使得组件中的事件被执行。
也就是说绑定到root上的事件监听listener只是相当于一个传令官,它按照事件的优先级去安排接下来的工作:事件对象的合成、将节点路径上的事件处理函数收集到执行路径、 事件执行, 这样在后面的调度过程中,scheduler才能获知当前任务的优先级,然后展开调度。
创建合成事件对象
React内部遵照W3C规范去实现一套事件系统,所以它的事件对象和原生事件对象并不相同。而原生的事件对象只不过是它的一个属性(nativeEvent)。
// 构造合成事件对象
const event = new SyntheticEvent(
reactName,
null,
nativeEvent,
nativeEventTarget,
EventInterface,
);
