React SyntheticEvent

基本概念

在react中,有一个很重要的概念就是:合成事件。他是基于Virtual DOM 所实现的一套事件系统。我们在React Element中所定义的事件,会作为合成事件来处理,其对应的事件处理函数,会接收到一个SyntheticEvent的实例。合成事件主要有如下的一些优势:

  1. 抹平各浏览器之间的事件差异,不存在兼容性问题,对开发者极为友好
  2. 合成事件利用冒泡机制,在顶层document完成事件注册和分发,避免直接操作DOM事件,减少内存开销,简化事件处理和回收机制。
  3. 内部使用事件池的概念,管理合成事件的创建,回收及其复用,提升性能。

任何一个合成事件对象都包含如下的基本属性:

boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type

如果在处理处理函数中,需要调用原生事件的话,可以通过nativeEvent 属性获取

所以在React中,遇到任何与事件相关的问题,首先要明确的就是:当前所触发的事件,到底是原生事件,还是合成事件?

Event Pooling

SyntheticEvent是被池化的,也就是说,SyntheticEvent对象是被复用的,在回调函数调用完成之后,所有的属性都会被取消,这主要是考虑到性能的原因。所以说,你在异步方法中,不能访问到事件对象。

当然,如果的确需要的话,可以调用event.persist(),该方法将会把合成事件从池中取出,始终在内存中保留对他的引用。

How

如下是一些实验,以及对合成事件实现原理的一些探索:

我们先做这样一个实验,在一个div上绑定click事件,如果不使用任何框架的话,一般会这样去定义:

const div = document.createElement('div');
div.onclick = function(){console.log(1)};
div.innerHTML='hello world';
document.body.appendChild(div);

通过浏览器审查工具,我们会看到,在div上绑定了一个click事件:
React SyntheticEvent_第1张图片
现在我们引入React,来实现同样的效果:
React SyntheticEvent_第2张图片
这时候,我们审查一下div的监听事件,会发现,
React SyntheticEvent_第3张图片
上面所看到的,在document上绑定的事件,其实就是合成事件的事件处理函数。但是为什么在div上还会绑定一个事件呢,通过检测该事件的定义,我们会发现,这其实是React为了处理移动端Safari的兼容性问题,而在div上绑定的一个空函数:
React SyntheticEvent_第4张图片
通过上面的测试结果我们就验证了,React并不会把事件处理函数直接绑定在真实的节点上,而是将所有的事件绑定在了结构的最外层,即document,使用一个统一的事件监听器,这个事件监听器上会维持一个事件的映射,来保存所有组件内的事件监听和处理函数。当有组件挂载或者卸载时,只是在这个事件监听器上插入或者删除一些对象。当有事件发生时,首先会被事件监听器处理,然后在映射里找到真实的事件处理函数并调用。

你可能感兴趣的:(react)