You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
// https://github.com/facebook/react/blob/v15.6.1/src/renderers/shared/stack/event/EventPluginUtils.jsfor(vari=0;i<dispatchListeners.length;i++){if(event.isPropagationStopped()){break;}// Listeners and Instances are two parallel arrays that are always in sync.if(dispatchListeners[i](event,dispatchInstances[i])){returndispatchInstances[i];}}
React合成事件
react为什么有合成事件的抽象?
如果DOM上绑定了过多的事件处理函数,整个页面响应以及内存占用可能都会受到影响。React为了避免这类DOM事件滥用,同时屏蔽底层不同浏览器之间的事件系统差异,实现了一个中间层——SyntheticEvent。
原理
React中,如果需要绑定事件,我们常常在jsx中这么写:
原理大致如下:
React并不是将click事件绑在该div的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行。
以上面的代码为例,整个事件生命周期示意如下:
其中,由于event对象是复用的,事件处理函数执行完后,属性会被清空,所以event的属性无法被异步访问,详情请查阅event-pooling。
如何在React中使用原生事件
虽然React封装了几乎所有的原生事件,但诸如:
等等场景时,不得不使用原生事件来进行业务逻辑处理。
由于原生事件需要绑定在真实DOM上,所以一般是在componentDidMount阶段/ref的函数执行阶段进行绑定操作,在componentWillUnmount阶段进行解绑操作以避免内存泄漏。
示例如下:
合成事件和原生事件混合使用
如果业务场景中需要混用合成事件和原生事件,那使用过程中需要注意如下几点:
响应顺序
先看个简单例子,下面例子中点击Demo以后,控制台输出会是怎样的?
我们来分析一下:首先DOM事件监听器被执行,然后事件继续冒泡至document,合成事件监听器再被执行。
即,最终控制台输出为:
阻止冒泡
那,如果在onDOMClick中调用evt.stopPropagation()呢?
由于DOM事件被阻止冒泡了,无法到达document,所以合成事件自然不会被触发,控制台输出就变成了
简单例子都比较容易理解,例子再复杂一些:
如果在onChildClick中调用evt.stopPropagtion(),则控制台输出变为:
这样的结果是因为React给合成事件封装的stopPropagation函数在调用时给自己加了个isPropagationStopped的标记位来确定后续监听器是否执行。
nativeEvent在React事件体系中的尴尬位置
有人或许有疑问,虽然响应顺序上合成事件晚于原生事件,那在合成事件中是否可以影响原生事件的监听器执行呢?答案是(几乎)不可能。。。
我们知道,React事件监听器中获得的入参并不是浏览器原生事件,原生事件可以通过evt.nativeEvent来获取。但令人尴尬的是,nativeEvent的作用非常小。
stopPropagation
在使用者的期望中,stopPropagation是用来阻止当前DOM的原生事件冒泡。
但通过上一节合成事件的原理可知,实际上该方法被调用时,实际作用是在DOM最外层阻止冒泡,并不符合预期。
stopImmediatePropagation
stopImmediatePropagation常常在多个第三方库混用时,用来阻止多个事件监听器中的非必要执行。
但React体系中,一个组件只能绑定一个同类型的事件监听器(重复定义时,后面的监听器会覆盖之前的),所以合成事件甚至都不去封装stopImmediatePropagation。
事实上nativeEvent的stopImmediatePropagation只能阻止绑定在document上的事件监听器。此外,由于事件绑定的顺序问题,需要注意,如果是在react-dom.js加载前绑定的document事件,stopImmediatePropagation也是无法阻止的。
【冷门】捕获阶段的合成事件
React支持将监听器注册在捕获阶段,但由于应用场景不多,所以基本不太被提及。不过本文涉及到了合成事件,就一并展开下。
后面再补充吧。。。。
结论
参考
1、https://juejin.im/post/59db6e7af265da431f4a02ef
2、react官方文档:http://react.html.cn/docs/events.html
The text was updated successfully, but these errors were encountered: