React事件机制与一般事件的混用

2,025 阅读3分钟

react的事件机制

react事件的核心内容就是事件委派,指所有的组件所有内部事件都绑定到结构的最外层,通常是document。在这个最外层上维持一个映射来保存所有组件内部的事件监听和处理函数。当事件发生的时候,先是被事件监听器捕捉,然后找到真正的事件处理函数。这么做主要的好处有 1.所有的事件都是挂载在一个元素上,可以极大的省去事件挂载的资源,就比如一个list有多个li,每个都需要挂载事件,这样挂载只需要挂一个事件,而如果对每一个li进行挂载,那么挂载的事件个数就会疯狂增加,是对内存的一种损耗 2.卸载事件的时候简洁而便利,回收机制只需要处理一个总的挂载资源就可以

具体阶段主要分为两个阶段1.事件注册2.事件触发 1.首先将事件注册在最外层 2.将事件的内容进行存储 2.通过dispatchEvent来进行事件派发 源码可见这篇文章 www.jianshu.com/p/c01756e52…

写法上借鉴的是Dom0的写法

<button onclick="hancleClick()"></button>

react中使用一般事件

但是我们在react开发过程中往往不能只用react事件体系,通常需要用到原生体系来解决一些问题,而用原生体系如果遗漏了一些细节的话,很容易导致一些问题。

因为react的事件体系无法很好的在组件内部绑定全局事件,所以全局事件用到原生绑定的概率是最高的,比如需要在window上绑定size事件,需要在document上绑定事件,除了这个之外一些比如点击除了某区域外的内容都会执行的事件也很适合用全局来进行绑定。

但是如果在使用原生事件的时候没有去把每一个事件进行回收的话,会造成内存溢出,因为react的router切换组件的时候会进行组件的卸载,然后再次进入的时候挂载,所以事件会多次进行绑定,针对一个线上的服务,内存溢出是一个很危险的点。

上面讲了react事件和一般事件混用内存溢出的问题,接下来讲第二个问题 大家可以想象这样一种场景,app上点击一块内容需要展示二维码,然后点击非二维码区域进行关闭。 这个按照我们正常的事件逻辑,处理方式有两种

  1. 在全局绑定点击事件,然后触发事件的时候判断class名称来判断是否触发逻辑
  2. 在全局绑定事件,在触发事件的时候通过阻止事件冒泡来进行处理 一般两者用的人都有,但是阻止冒泡在理解之后处理起来比较简单
//核心代码
componentDidMount(){
    document.body.addEventListener('click',e=>{
        this.setState({
            qrActive:true
        })
    })
}

handleClickQr(e){
    e.stopPropagation();
}

然而大家回去试一下,可以发现,具体的结果呈现和你想象中的并不一致,你点击二维码区域也会把二维码隐藏起来,这是为什么呢?冒泡机制没有成功被打断?

其实并不是,如果你还记得刚刚说的react事件机制就能知道,react的事件就是统一挂载在顶级dom上的,所以react的事件机制根本没有经历你想象中的从顶级元素到二维码的捕获,目标,冒泡阶段,所以阻止事件冒泡并不能阻止body绑定的click事件的执行,如果你想要进行上述的逻辑判断,还是要使用第一种处理方式.

但是原生组件的阻止冒泡行为却可以阻止react事件合成机制.