React事件处理的机制及原理


Posted in Javascript onDecember 03, 2018

React中的事件处理

在React元素中绑定事件有两点需要注意:

(1)在React中,事件命名采用驼峰命名方式,而不是DOM元素中的小写字母命名方式。例如onclick要写成onClick,onchange要写成onChange等。
(2)处理事件的响应函数要以对象的形式赋值给事件属性,而不是DOM中的字符串形式。例如在DOM中绑定一个点击事件应该写成:

<button onclick="clickButton()">
  Click
</button>

而在React元素中绑定一个点击事件变成这种形式:

<button onClick={clickButton}> // clickButton是一个函数
  Click
</button>

React中的事件是合成事件,并不是原生的DOM事件。

React根据W3C规范定义了一套兼容各个浏览器的事件对象。在DOM中可以通过返回false来阻止事件的默认行为,但在React中,必须显式的调用事件对象的preventDefault方法来阻止事件的默认行为。

在某些场景下如果必须使用DOM提供的原生事件,可以通过React事件对象的nativeEvent属性获取。

其实,在平时的开发中,React组件中处理事件最容易出错的地方是事件处理函数中的this的指向问题,因为ES6 class并不会为方法自动绑定this到当前对象。

下面我们具体来看一下常见的三种处理this的方式:

React事件处理的this处理

使用箭头函数

直接在React元素中采用箭头函数定义事件的处理函数,如:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    }
  }

  render() {
    return (
      <button onClick={(event) => {
          console.log(this.state.number);
        }}>
        Click
      </button>
      )
  }
}

箭头函数中的this指向的是函数定义时的对象,所以可以保证this总是指向当前组件的实例对象。

当事件处理逻辑比较复杂时,如果把所有的逻辑直接写在onClick的大括号中,就会导致render函数变的臃肿,不容易直观地看出组件的UI结构,代码可读性也不好。这样,我们可以把逻辑处理封装成组件的一个方法,然后在箭头函数中调用该方法即可。

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    }
  }

  handleClick(event) {
    const number = ++this.state.number;
    this.setState({
      number: number
    });

  }

  render() {
    return (
      <button onClick={(event) => {
          this.handleClick(event);
        }}>
        Click
      </button>
      )
  }
}

直接在render方法中为元素事件定义事件处理函数,最大的问题是,每次render调用时,都会重新创建一个新的事件处理函数,带来额外的性能开销,组件所处层级越低,这种开销就越大。当然,大多数情况下,这种开销是可以接受的。

使用组件方法

直接将组件的方法赋值给元素的事件属性,同时在类的构造函数中,将这个方法的this绑定到当前对象。如:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(event) {
    const number = ++this.state.number;
    this.setState({
      number: number
    });

  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click
      </button>
      )
  }
}

这种方法的好处是每次render不会重新创建一个回调函数,没有额外的性能损失。但在构造函数中,为事件处理函数绑定this,尤其是存在多个事件处理函数需要绑定时,这种模板式的代码还是会显得繁琐。

有时候我们还会为元素的事件属性赋值时,同时为事件处理函数绑定this,例如:

class MyComponent extends React.Component {
  
  ……

  render() {
    return (
      /* 事件属性赋值和this绑定同时 */
      <button onClick={this.handleClick.bind(this)}>
        Click
      </button>
      )
  }
}

使用bind会创建一个新的函数,因此这种写法依然存在每次render都会创建一个新函数的问题。但是在需要为函数传入额外的参数时,这种写法就比较方便了。

class MyComponent extends React.Component {
  
  ……

  render() {
    const type = 1;
    return (
      /* 事件属性赋值和this绑定同时 */
      <button onClick={this.handleClick.bind(this, type)}>
        Click
      </button>
      )
  }
}

属性初始化语法

使用ES7的property initializers会自动为class中定义的方法绑定this。例如:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      number: 0
    };
  }

  handleClick = (event) => {
    const number = ++this.state.number;
    this.setState({
      number: number
    });

  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click
      </button>
      )
  }
}

这种方式既不需要在构造函数中手动绑定this,也不需要担心组件重复渲染导致的函数重复创建的问题。不过由于property initializers 这个特性还处于试验阶段,默认有些浏览器是不支持的,需要使用babel来进行支持。

通过上面我们可以看到,只要处理好了React组件中函数的this绑定问题,React的事件处理就没有太大的问题了。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javaScript 动态访问JSon元素示例代码
Aug 30 Javascript
利用毫秒减值计算时长的js代码
Sep 22 Javascript
简单常用的幻灯片播放实现代码
Sep 25 Javascript
使用js检测浏览器是否支持html5中的video标签的方法
Mar 12 Javascript
鼠标移到图片上变大显示而不是放大镜效果
Jun 15 Javascript
checkbox选中与未选中判断示例
Aug 04 Javascript
JavaScript中的toDateString()方法使用详解
Jun 12 Javascript
Sort()函数的多种用法
Mar 20 Javascript
详解微信小程序设置底部导航栏目方法
Jun 29 Javascript
基于javascript的拖拽类封装详解
Apr 19 Javascript
Vue的编码技巧与规范使用详解
Aug 28 Javascript
如何利用node.js开发一个生成逐帧动画的小工具
Dec 01 Javascript
JointJS流程图的绘制方法
Dec 03 #Javascript
微信小程序之事件交互操作实例分析
Dec 03 #Javascript
vue-better-scroll 的使用实例代码详解
Dec 03 #Javascript
Vue项目中使用better-scroll实现一个轮播图自动播放功能
Dec 03 #Javascript
Vue.js 图标选择组件实践详解
Dec 03 #Javascript
vue-music 使用better-scroll遇到轮播图不能自动轮播问题
Dec 03 #Javascript
vue-cli3.0+element-ui上传组件el-upload的使用
Dec 03 #Javascript
You might like
yii2 在控制器中验证请求参数的使用方法
2019/06/19 PHP
js replace正则表达式应用案例讲解
2013/01/17 Javascript
Jquery中使用setInterval和setTimeout的方法
2013/04/08 Javascript
javascript date格式化示例
2013/09/25 Javascript
用Js实现的动态增加表格示例自己写的
2013/10/21 Javascript
Javascript中的arguments与重载介绍
2015/03/15 Javascript
JS实现获取当前URL和来源URL的方法
2016/08/24 Javascript
JS函数多个参数默认值指定方法分析
2016/11/28 Javascript
详解一个基于react+webpack的多页面应用配置
2019/01/21 Javascript
Vue Prop属性功能与用法实例详解
2019/02/23 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
JS实现iframe中子父页面跨域通讯的方法分析
2020/03/10 Javascript
Vue列表如何实现滚动到指定位置样式改变效果
2020/05/09 Javascript
[03:07]2015国际邀请赛选手档案EHOME.rOtK 是什么让他落泪?
2015/07/31 DOTA
[01:05:36]VP vs TNC Supermajor小组赛B组 BO3 第二场 6.2
2018/06/03 DOTA
[37:47]IG vs Winstrike 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
[01:02:45]完美世界DOTA2联赛 LBZS vs Forest 第三场 11.07
2020/11/09 DOTA
利用Tkinter和matplotlib两种方式画饼状图的实例
2017/11/06 Python
Python微医挂号网医生数据抓取
2019/01/24 Python
python实发邮件实例详解
2019/11/11 Python
Python算法中的时间复杂度问题
2019/11/19 Python
基于python修改srt字幕的时间轴
2020/02/03 Python
python框架flask入门之环境搭建及开启调试
2020/06/07 Python
python进行OpenCV实战之画图(直线、矩形、圆形)
2020/08/27 Python
python 深度学习中的4种激活函数
2020/09/18 Python
CSS3与动画有关的属性transition、animation、transform对比(史上最全版)
2017/08/18 HTML / CSS
美国亚马逊旗下时尚女装网店:SHOPBOP(支持中文)
2020/10/17 全球购物
应届毕业生自荐信
2014/05/28 职场文书
教师党的群众路线教育实践活动个人整改措施
2014/11/04 职场文书
2015年征兵工作总结
2015/07/23 职场文书
2016社区平安家庭事迹材料
2016/02/26 职场文书
求职自我评价参考范文
2019/05/16 职场文书
html5中sharedWorker实现多页面通信的示例代码
2021/05/07 Javascript
Python中json.load()和json.loads()有哪些区别
2021/06/07 Python
javascript实现计算器功能详解流程
2021/11/01 Javascript
MySQL控制流函数(-if ,elseif,else,case...when)
2022/07/07 MySQL