react事件绑定的方式和区别(react合成事件与原生事件的相关理解)
react事件绑定的方式和区别
react合成事件与原生事件的相关理解目录
- 1. 原生事件
- 2. 合成事件
- 为什么react事件需要手动绑定this
- 3. 原生与合成事件触发顺序
- 4. 合成事件和原生事件混用
- 相关疑问:
- e.nativeEvent.stopPropagation
- e.nativeEvent.stopImmediatePropagation
原生事件就是js的原生事件,如通过document.addEventListener来设置的监听事件。
在react中即使有自己的一套事件机制(见下面合成事件),但有时候的业务场景我们仍然需要使用原生事件。比如我们封装一个Modal弹窗组件,需要在点击非弹窗区域时关掉弹窗,此时我们只能针对document进行原生点击事件监听。
由于原生事件需要绑定在真实DOM上,所以一般是在componentDidMount阶段或者组件/元素的ref的函数执行阶段进行绑定操作,并且注意要在componentWillUnmount阶段进行解绑操作以避免内存泄漏。
2. 合成事件React有自己的一套事件机制,它重新封装了绝大部分的原生事件。合成事件采用了事件池,这样做可以大大节省内存,而不会频繁的创建和销毁事件对象。
在React中,如果需要绑定事件,我们常常在jsx中这么写:
handleClick(){ } <li onClick={this.handleClick.bind(this)}> react事件 </li>
大致原理:
React并不是将click事件绑在该li的真实DOM上,而是在document处监听所有支持的事件,当事件发生并冒泡至document处时,React将事件内容封装并交由真正的处理函数运行。
以上面的代码为例,整个事件生命周期示意如下:
合成事件的一些特点总结:
- React 上注册的事件最终会绑定在document这个 DOM 上,而不是 React 组件对应的 DOM(减少内存开销就是因为所有的事件都绑定在 document 上,其他节点没有绑定事件)
- React 通过队列的形式,从触发的组件向父组件回溯,然后调用他们 JSX 中定义的 callback
- React 通过对象池的形式管理合成事件对象的创建和销毁,减少了垃圾的生成和新对象内存的分配,提高了性能
了解react合成事件的大概原理后,方便我们解答下面一个问题:
为什么react事件需要手动绑定this
合成事件触发之后会冒泡一路到document的节点,然后开始分发document节点收集到的事件,这个时候react从事件触发的组件实例开始, 遍历虚拟dom树,从树上取下我们绑定的事件,收集起来,然后执行。举个例子:
class Test extends React.Component { fatherHandler = function father() { /*...*/} childHander = function child() {/*...*/} render(){ return ( <li onClick={this.fatherHandler}> <span onClick={this.childHander}> </span> </li> ); } }
当事件触发以后react会把上面的事件处理函数放到一个数组里是这样的
[father, child]
最后,react只要遍历执行这个数组,就能执行所有需要执行的事件处理函数。这里react对函数进行了临时保存,这个时候执行的话,this自然就丢失了。
如果react保存顺便保存一下实例,还是可以做到,不需要你绑定this的,但是这样对于react来说代价太大了。
3. 原生与合成事件触发顺序componentDidMount() { this.parent.addEventListener('click', (e) => { console.log('dom parent'); }) this.child.addEventListener('click', (e) => { console.log('dom child'); }) document.addEventListener('click', (e) => { console.log('document'); }) } childClick = (e) => { console.log('react child'); } parentClick = (e) => { console.log('react parent'); } render() { return ( <li onClick={this.parentClick} ref={ref => this.parent = ref}> <li onClick={this.childClick} ref={ref => this.child = ref}> test </li> </li>) }
点击child中的test后,事件触发顺序如下:
结论:
无论是否是对于同一元素监听的同种类型事件,原生事件总是比合成事件先触发。这是由于上面我们说到的合成事件最终都会绑定到documnet DOM上导致的,当合成事件监听到后,总是冒泡到document才会真正触发。 而documnet DOM上监听的原生事件则总是最后触发
4. 合成事件和原生事件混用react合成事件和原生事件最好不要混用。
原生事件中如果执行了stopPropagation(阻止冒泡)方法,则很容易导致其他同类型react合成事件失效。因为这样所有同级以及后代元素的合成事件和原生事件都将无法冒泡到document上。
而如果仅仅是合成事件中使用了e.stopPropagation(阻止冒泡)方法,则不会影响原生事件的冒泡
相关疑问:
我们知道React事件监听器中获得的入参并不是浏览器原生事件,原生事件可以通过e.nativeEvent来获取。通过这种方式,合成事件可以影响原生事件吗?
e.nativeEvent.stopPropagation
即使在react的合成事件中调用原生事件的阻止冒泡,实际作用是在DOM最外层阻止冒泡,并不符合预期。也就是说它最终只能控制当前监听的合成事件不会冒泡到document DOM的原生事件
e.nativeEvent.stopImmediatePropagation
该方法与上面的nativeEvent.stopPropagation有类似的功能,都可阻止当前监听的合成事件冒泡到document DOM的原生事件
stopImmediatePropagation常常在多个第三方库混用时,用来阻止多个事件监听器中的非必要执行。比如同一个元素的同种事件,设置了多个监听事件函数,则该方式可以控制监听函数只触发第一个
stopImmediatePropagation和stopPropagation本都是原生事件,但在React自己的事件体系中,重新封装了后者,却没有封装前者。导致在合成事件中只能手动调用nativeEvent.stopImmediatePropagation。
因为在React的合成事件机制中,一个组件只能绑定一个同类型的事件监听器(重复定义时,后面的监听器会覆盖之前的),所以合成事件无需去封装stopImmediatePropagation。
所以,在React的合成事件中,e.nativeEvent.stopPropagation和e.nativeEvent.stopImmediatePropagation实际的作用是等价的
此外,由于事件绑定的顺序问题,需要注意,如果是在react-dom.js加载前绑定的document原生事件,stopImmediatePropagation也是无法阻止的。
以上就是react合成事件与原生事件的相关理解的详细内容,更多关于react合成事件与原生事件的资料请关注开心学习网其它相关文章!
- react动态创建菜单并实现局部刷新(使用react-virtualized实现图片动态高度长列表的问题)
- react中state的作用是什么(React中useEffect 与 useLayoutEffect的区别)
- react动态添加组件属性(react使用antd的上传组件实现文件表单一起提交功能完整代码)
- react路由原理解析(React配置子路由的实现)
- react路由组件怎么用(无废话快速上手React路由开发)
- reacthooks基础使用(React 小技巧教你如何摆脱hooks依赖烦恼)
- vue3 props用法(vue3组合API中setup、 ref、reactive的使用大全)
- react怎么使用父组件(关于antd tree和父子组件之间的传值问题react 总结)
- react的基本知识(React中refs的一些常见用法汇总)
- vscode react jsx语法 开发环境(React-vscode使用jsx语法的问题及解决方法)
- react 分页列表优化(使用react-beautiful-dnd实现列表间拖拽踩坑)
- reactnative混合开发教程(教你使用vscode 搭建react-native开发环境)
- react表单组件怎么写(react antd实现动态增减表单)
- react基础知识详解(如何深入理解React的ref 属性)
- react加载优化(React星星评分组件的实现)
- react绑定详解(React列表栏及购物车组件使用详解)
- 吴启华与曾舜晞两代张无忌同框,戏里经典的他却没活出原著的潇洒(吴启华与曾舜晞两代张无忌同框)
- 经常发这三种 朋友圈 的人,要迅速屏蔽(经常发这三种朋友圈)
- 有种尴尬叫朋友圈忘屏蔽,大学生上演社死现场,父母亲自下场吐槽(有种尴尬叫朋友圈忘屏蔽)
- 朋友圈屏蔽你的人,可以直接看淡了(朋友圈屏蔽你的人)
- 金球奖只青睐那些会戴珠宝的女人(金球奖只青睐那些会戴珠宝的女人)
- 浙江省一个县,人口超40万,建县历史超1100年(浙江省一个县人口超40万)
热门推荐
- dedecms搜索功能的实现(DEDECMS调用特定ID文章内容的实现方法)
- web服务器配置怎么选才是合适的呢(个人web服务器要用哪种服务器比较好?)
- 阿里云服务器ecs怎么设置(如何解决阿里云ECS服务器误开启了防火墙导致远程连接不上的问题)
- web服务器与应用服务器的区别(web服务器是什么?web服务器有哪些呢?)
- linuxdocker启动报错提示参数无效(docker 报错 Exited 1 4 minutes ago的原因分析)
- docker-compose部署实例(详解docker-compose速度太慢解决方式)
- 对mysql性能优化的看法(聊聊MySQL的COUNT的性能,看看怎么最快?)
- 用mysql编写test数据库(MySQL制作具有千万条测试数据的测试库的方法)
- python串口怎么使用(使用Python3+PyQT5+Pyserial 实现简单的串口工具方法)
- 微信小程序图片加特效(微信小程序实现可实时改变转速的css3旋转动画实例代码)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9