React中的事件模型

与浏览器原生的事件不同React中的事件属于合成事件,是由React提供的,首先我们看一下浏览器原生的事件模型

DOM事件模型

DOM事件分为三个阶段

  1. 事件捕获
  2. 事件目标处理函数
  3. 事件冒泡

当事件触发的时候,首先由document发出一个事件流,通过DOM树一层层到达目标DOM这个阶段属于事件捕获,到达触发事件DOM这个阶段是执行处理函数,接下来从目标DOM返回到document这个阶段称为事件冒泡阶段。

一般情况下我们的事件处理函数在事件冒泡阶段执行,addEventListener API的第三的参数接收一个boolean值 允许我们制定事件是否在捕获阶段执行,默认是false。

我们可以调用 event.stopPorpagation()来组织事件冒泡 IE下使用 event.cancel = true

使用事件对于浏览器来说是一个相对来说比较消耗性能的操作,而且当绑定事件的DOM从页面中移除的时候我们需要手动接触事件监听以防止出现内存泄漏的问题。

当一个列表中的每一个item都需要绑定事件的时候,如果每一个item都绑定事件就不是一个好的方法,一来我们需要对多个事件监听进行绑定和移除,二来多个事件监听浪费了更多的内存影响浏览器性能。

解决方法就是使用事件委托思想,利用事件冒泡机制,在所有item的外层添加一个事件处理函数,然后根据event对象的target属性来判断真实触发事件的DOM,这样就只需要一个事件处理函数,降低了维护成本,也提高了页面的性能。

事件委托也存在局限的地方因为是依赖事件冒泡原理实现的,但是有些事件是不支持事件冒泡的,那么这些事件也就无法使用代理机制。


React中的合成事件

React将所有类型的事件绑定到document上,使用全局统一的事件监听器,这个事件监听器维护了所有React事件和处理函数的映射关系,当组件绑定事件时,就会在这个映射关系上插入一个对象,当组件卸载时,在这个映射关系上删除一个对象,这样就不会频繁的绑定和卸载事件监听,只需要维护这个映射关系就可以了。

当触发事件时,我们知道事件的类型和触发事件的React component,我们找到这个React component,如果事件是支持冒泡的,那我们还需要findParent找到它的父节点,这个过程一直重复到parent是document,然后事件就沿着这个路线一直到document,当然我们也可以使用event.stopPropagation()阻止事件冒泡,因为event对象经过封装所以stopPropagation方法在IE下也可以使用没有兼容性问题。