窥探react事件

news/2024/7/1 8:01:00

写在前面

本文源于本人在学习react过程中遇到的一个问题;本文内容为本人的一些的理解,如有不对的地方,还请大家指出来。本文是讲react的事件,不是介绍其api,而是猜想一下react合成事件的实现方式

遇到的问题

class EventTest extends Component {handleParentClick(e) {console.log('click parent div');}handleChildClick(e) {e.stopPropagation();console.log('click child div');}componentDidMount() {document.querySelector('.parent').addEventListener('click', this.handleParentClick);}render() {return (<div className="parent"><div className="child" onClick={this.handleChildClick}></div></div>);}
}

上述代码render出来后,尝试点击一下div.child,诡异的现象产生了:

clipboard.png

控制台中输出如上图所示,这完全不符合浏览器的事件执行啊,我所期望的是指输出click child div,因为已经利用了e.stopPropagation()来阻止冒泡,说明阻止冒泡失效了,但是仅仅如此吗,可以发现的是首先输出的是click parent div(wtf)。

解决问题

为了解决上述问题,先来了解下react的事件,react事件是合成事件,为原生事件的一个子集,仅仅是进行了一个跨浏览器的封装。但是真的只有这么简单?图样图森破。
利用控制台,看下div.child对应的事件处理函数:

clipboard.png

一个空函数,事件的监听函数不是所定义的handleChildClick,而是emptyFunction,也就是说react没有在真实的DOM节点上绑定事件(在DOM节点上绑定事件比较消耗内存,因为当dom节点被remove后,虽然不存在与dom tree中,但是仍存在与内存中,需要手动remove事件orchild = null),react的合成事件利用的是事件代理方式实现,也就是说会将事件监听器绑定到整个文档document上,是不是这样呢?来验证一下,利用chrome:

clipboard.png

可以发现,document上的确被绑定了click事件,dom节点的真实的事件处理函数全部以一个特定的结构存储在了内存中,当点击div.child时,这时其事件处理函数为emptyFunction,执行这个函数无任何作用,按照浏览器标准事件模型,开始向上冒泡,这时到了div.parent,于是输出了click parent div,一直向上到了document,这时根据e.target进行处理,而react并不会根据dom层级式传播那样遍历virtual dom结构,这样有时遍历的层级会很多,而且会有很多的无效遍历。

react是怎么做的呢?

react依靠每个React component各自独立的id来编码这个层级。这样就能通过简单的字符串操作来获取所有父级 component 的父级内容,再把事件监听存储在hashmap当中,比如有如下结构并且为没一层div添加onClick

div.adiv.bdiv.c

当点击div.c时,处理方式:

clickBubbleListeners['a.b.c'](event);
clickBubbleListeners['a.b'](event);
clickBubbleListeners['a'](event);

在合成事件中用e.stopPropagation只能阻断上述冒泡过程。

结论

由此可以看出:

  • 阻止react事件冒泡的行为只能用于react合成事件中,对于原生事件无效(合成事件中的e.stopPropagation与原生事件中的e.stopPropagation并不是一回事)

  • 阻止原生事件的冒泡行为,可以阻止react合成事件的传播(根本不会冒泡到document上,所以不会触发react的合成事件)

  • 在写react时,最好不要将合成事件与原生事件混用

参考

本文部分参考自IMWeb—React事件初探


http://lihuaxi.xjx100.cn/news/241720.html

相关文章

SQL Server 运行计划操作符具体解释(2)——串联(Concatenation )

本文接上文&#xff1a;SQL Server 运行计划操作符具体解释&#xff08;1&#xff09;——断言(Assert)前言&#xff1a;依据计划。本文開始讲述另外一个操作符串联&#xff08;Concatenation&#xff09;。读者能够依据这个词&#xff08;中英文均可&#xff09;先幻想一下是干…

UI培训分享:如何成为一名优秀的UI设计师

UI设计师在工作岗位中也是分等级的&#xff0c;如何成为一名优秀的UI设计师在如今的职业发展中是非常有必要的&#xff0c;各行各业都在内卷中&#xff0c;那么如何成为一名优秀的UI设计师呢?来看看下面的详细介绍。 UI培训分享&#xff1a;如何成为一名优秀的UI设计师? 好UI…

2017.1.9版给信息源新增:max_len、max_db字段

2017.1.8a版程序给信息源增加max_len、max_db字段&#xff0c;分别用于控制&#xff1a;获取条数、数据库保留条数。 max_len的说明见此图&#xff1a; max_db的说明见此图&#xff1a; 当max_len和max_db的设置不合理时&#xff08;比如max_len大于max_db&#xff0c;会导致反…

(C++)设计一个程序能计算一个日期加上若干天后是什么日期and计算日期差值

输入第一行表示样例个数m&#xff0c;接下来m行每行四个整数分别表示年月日和累加的天数。 输出m行&#xff0c;每行按yyyy-mm-dd的个数输出。 #include<cstdio>//判断是否是闰年 bool isLeap(int year){return (year%40&&year%100!0)||year%4000; }//用二维数…

删除字符串中出现次数最少的字符

在公交车上看一博客实现删除字符串中出现次数最少的字符&#xff0c;认为里面使用数组来作为hash很好&#xff0c;所以我就自己实现一遍。要求&#xff1a;实现删除一个字符串中出现次数最少的字符。输出删除后的字符&#xff0c;要求安装原来顺序输出。假设出现次数一样&#…

软件测试培训分享:软件测试的职业发展方向有哪些

很多人都觉得软件测试在互联网行业入门是比较轻松的&#xff0c;对于如此轻松的行业&#xff0c;它所在的职业发展前景怎么样呢?软件测试的职业发展方向有哪些呢?本期软件测试培训分享内容请看以下详细介绍。 软件测试的职业发展方向有哪些?职业的选择对于现在的年轻人来说相…

(C++)CSP202006-2 稀疏向量 two pointers

#include<cstdio>const int M 500000;//a,b<5*10^5 int u[M1][2];//第一维是index,第二维是value int v[M1][2];int main(){//1.读入n,a,b//2.对数组进行遍历&#xff0c;如果第一位相等&#xff0c;将第二维相乘 int n,a,b,i;long long ans0;scanf("%d%d%d&qu…

C# GUID的使用

GUID&#xff08;全局统一标识符&#xff09;是指在一台机器上生成的数字&#xff0c;它保证对在同一时空中的所有机器都是唯一的。通常平台会提供生成GUID的API。生成算法很有意思&#xff0c;用到了以太网卡地址、纳秒级时间、芯片ID码和许多可能的数字。GUID的唯一缺陷在于生…