事件系统

Virtual DOM在内存中是以对象的形式存在,如果想要在这些对象上加事件就会比较简单。React基于Virtual DOM实现了一个合成事件层,我们所定义的事件会接受到一个合成事件对象的实例。不会存在IE浏览器兼容性的问题,同样支持事件冒泡机制。

合成事件绑定方式

React事件的绑定方式在写法上与原生HTML事件监听很相似。

<button onClick={this.handleClick}></button>

这个和JavaScript的DOM0级事件很像,但是又有一些不同:HTML的事件需要全部小写的属性名,而且jsx的属性值可以是任何类型。这里是一个函数指针。

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

React并不会像DOM0级事件那样将事件处理器直接绑定到DOM上,React仅仅是借鉴了这种写法。

合成事件的实现机制

在React底层,主要对合成事件做了两件事情:事件委派和自动绑定。

1. 事件委派

React中并不是把事件处理函数绑定到当前DOM上,而是把所有的事件绑定到结构的最外层,使用统一的事件监听器。
这个事件监听器上维持了一个映射来保存所有组件内部的事件监听和处理函数。
组件挂载和卸载时,只是在统一事件监听器上插入删除一些对象。

2. 自动绑定

在React组件中,每个方法的上下文都会指向该组件的实例,即自动绑定this为当前的组件。而且React会对这种引用缓存,以达到CPU和内存的最大优化。
注意:在使用es6 class或者纯函数的写法,这种绑定不复存在,我们需要手动实现this绑定。

  • bind方法:该方法可以帮助我们绑定事件处理器内的this,并可以向事件处理器中传入参数:
class App extends Component {handleClick(e, arg) {console.log(e, arg)}render() {return <button onClick={this.handleClick.bind(this, 'test')}></button>}
}

如果只绑定方法,不传递参数,stage0提供一个双冒号语法:

class App extends Component {handleClick(e) {console.log(e)}render() {return (<button onClick{::this.handleClick}></button>)}
}
  • 构造器内声明:在组件的构造器内完成this的绑定,这种绑定的好处在于仅仅需要进行一次绑定,而不需要每次调用事件监听器的时候去执行绑定操作。
import React, {Component} from 'react'class App extends Component {constructor(props) {super(props)}handleClick(e) {console.log(e)}render() {return (<button onClick={this.handleClick}></button>)}
}
  • 箭头函数:箭头函数自动绑定了定义此函数作用域的this,因此我们不需要再对它使用bind方法。
class App extends Component {const handleClick = (e) => {console.log(e)}render() {return (<button onClick={this.handleClick}></button>)}
}

如上集中方法,都能实现在类定义的组件中绑定this上下文的效果。

在React中使用原生事件

我们可以在componentDidMount方法中完成原生事件的绑定,此时组件已经安装完成并且在浏览器中存在真实的dom。

class App extends Component {componentDidMount() {this.refs.button.addEventListener('click', e => {this.handleClick()})}handleClick(e) {console.log(e)}componentWillUnmount() {this.refs.button.removeEventListener('click')}render() {return <button ref='button'></button>}
}

在React中使用DOM原生事件时,一定要在组件卸载时手动移除,否则很有可能出现内存泄漏的问题。然而合成事件在内部已经很好的帮我们处理过了。

合成事件与原生事件混用

reactEvent.nativeEvent.stopPropagation()只能用于React合成事件系统中,没办法阻止原生事件的冒泡。原生事件阻止冒泡行为可以阻止React合成事件的传播。

React合成事件系统只是原生DOM事件系统的一个子集,它仅仅实现了DOM LEVEL3事件接口,并且统一了浏览器的兼容性问题。

对比合成事件与JavaScript原生事件

我们从4个方面来对比React合成事件与JavaScript原生事件。

  • 事件传播与阻止事件传播

浏览器原生DOM事件的传播可以分为3个阶段:事件捕获阶段、目标对象本身事件处理程序、事件冒泡阶段
事件捕获会优先调用结构树最外层的元素上绑定的事件监听器,然后依次向内调用,一直调用到目标元素上的事件监听器为止。可以在e.addEventListener()的第三个参数设置为true时,为元素e注册捕获事件处理程序,并且在事件传播的第一个阶段调用。事件捕获在低于IE9的浏览器中不支持。
事件冒泡和事件捕获相反,它会从目标元素向外传播,由内而外直到最外层。

React合成事件中没有实现事件捕获,仅仅支持事件冒泡机制。

阻止原生事件传播需要使用e.preventDefault(),不过对于不支持的浏览器可以使用e.cancelBubble = true来阻止。React合成事件中使用e.preventDefault()即可。

  • 事件类型

React合成事件的事件类型是JavaScript原生事件类型的子集。

  • 事件绑定方式

原生事件绑定的方式如下:

1. <button onclick="alert(1)">btn</button>
2. e.onclick = function() {}
3. e.addEventListener()

React事件绑定方式比较简单:

<button onClick={this.handle.bind(this)}></button>
  • 事件对象

原生DOM事件对象在不同浏览器中存在着差异。在低版本的IE浏览器中,只能使用window.event来获取事件对象。React中不存在这些差异,在事件处理函数中可以得到一个合成事件对象。

React事件系统整理相关推荐

  1. 通俗易懂的React事件系统工作原理

    前言 React 为我们提供了一套虚拟的事件系统,这套虚拟事件系统是如何工作的,笔者对源码做了一次梳理,整理了下面的文档供大家参考. 在 React事件介绍 中介绍了合成事件对象以及为什么提供合成事件 ...

  2. 深入React事件系统(React点击空白部分隐藏弹出层;React阻止事件冒泡失效)

    只关注括号内问题的同学,可直接跳转到蓝字部分.(标题起的有点大,其实只讨论一个问题) 两个在React组件上绑定的事件,产生冲突后,使用e.stopPropagation(),阻止冒泡,即可防止事件冲 ...

  3. React学习整理(一):React 安装

    官方提供的 CDN 地址: <script src="https://unpkg.com/react@16/umd/react.development.js">< ...

  4. [React网络整理]React之表单组件的学习笔记

    表单组件 诸如 <input>.<textarea>.<option> 这样的表单组件不同于其他组件,因为他们可以通过用户交互发生变化.这些组件提供的界面使响应用户 ...

  5. 浅析React之事件系统(二)

    上篇文章中,我们谈到了React事件系统的实现方式,和在React中使用原生事件的方法,那么这篇文章我们来继续分析下,看看React中合成事件和原生事件混用的各种情况. 上一个例子 在上篇文章中,我们 ...

  6. React源码分析7 — React合成事件系统

    1 React合成事件特点 React自己实现了一套高效的事件注册,存储,分发和重用逻辑,在DOM事件体系基础上做了很大改进,减少了内存消耗,简化了事件逻辑,并最大化的解决了IE等浏览器的不兼容问题. ...

  7. 整理下react.hooks

    React HOOKS 整理内容 来自B站eeerinzhang https://www.bilibili.com/video/BV1JE411f7kV?t=838 阮一峰博客hooks 开发流程(改 ...

  8. jquery 监听td点击事件_React 事件 | 1. React 中的事件委托

    说到 React 的事件,也算是 React 的一个非常有亮点的优化,它在原生事件体系的基础上,单独实现了一套事件机制.想要了解这个机制,首先的了解下什么是事件委托以及事件委托的好处. 事件委托 假设 ...

  9. 从源码全面剖析 React 组件更新机制

    React 把组件看作状态机(有限状态机), 使用state来控制本地状态, 使用props来传递状态. 前面我们探讨了 React 如何映射状态到 UI 上(初始渲染), 那么接下来我们谈谈 Rea ...

最新文章

  1. PCL、XPS转换成PDF的控件activePDF Meridian​
  2. java程序设计题目_Java程序设计习题集(含答案).doc
  3. sts在文件夹中显示_工作中很多问题,巧用Windows 10任务栏,几分钟快速解决
  4. 【ruoyi若依】为当前页添加显示事件
  5. 二叉树的锯齿形层次遍历—leetcode103
  6. 函数实现不放在头文件的原因,及何时可以放头文件的情况
  7. java 枚举 菜鸟_2个菜鸟Java常量和枚举陷阱
  8. 前端学习(2844):ui另一种按需加载
  9. office教程:教你Excel 怎么样使用信息函数
  10. php 循环 显示 图片,thinkphp 循环显示图片问题!!!~~~~
  11. 快速排序quicksort算法优化
  12. Start with...Connect By子句递归查询一般用于一个表维护树形结构的应用。
  13. 贵大计算机学院陈力,CCF贵州大学学生分会完成换届
  14. rost反剽窃检测系统_论文为什么需要进行查重检测?
  15. 人工智能时代的风口项目,电话机器人源码和系统部署
  16. 数学分析教程(科大)——2.8笔记+习题
  17. python2与python3实现读取网页刷访问量
  18. aix for sqlserver_Oracle大型数据库系统在AIX/UNIX上的实战详解(第2版)(文平)高清PDF扫描版 [266.16M]...
  19. 【周记】腾讯犀牛鸟「云开发」校园技术布道师养成计划
  20. 东北女子参加同学聚会倒地猝死,无人参与急救

热门文章

  1. SAP WM Picking Area的使用
  2. SAP PP 启用了HU管理下的工单入库
  3. 用于EAM的SAP PM移动应用程序
  4. 一位人工智能总监对AI行业的【实话实说】
  5. 「NLP」 深度学习NLP开篇-循环神经网络(RNN)
  6. 用泰勒级数来估计函数的近似值
  7. 人工智能医疗是把双刃剑,“对抗性攻击”后可导致误判
  8. 科大讯飞董事长:AI创业,做平台已没有机会
  9. 机器学习笔记十:各种熵总结
  10. MachineLN博客目录