在React中如何优雅的处理事件响应详解


Posted in Javascript onJuly 24, 2017

前言

本文主要给大家介绍的是关于React处理事件响应的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍吧。

React中定义一个组件,可以通过React.createClass或者ES6的class。本文讨论的React组件是基于class定义的组件。采用class的方式,代码结构更加清晰,可读性强,而且React官方也推荐使用这种方式定义组件。

处理事件响应是Web应用中非常重要的一部分。React中,处理事件响应的方式有多种。

一、使用箭头函数

先上代码:

//代码1
class MyComponent extends React.Component {

 render() {
 return (
  <button onClick={()=>{console.log('button clicked');}}>
  Click
  </button>
 );
 }
}

当事件响应逻辑比较复杂时,再把所有的逻辑直接写在onClick的大括号内,就会导致render函数变得臃肿,不容易直观地看出组件render出的元素结构。这时,可以把逻辑封装成组件的一个方法,然后在箭头函数中调用这个方法。

如下所示:

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

 handleClick() {
 this.setState({
  number: ++this.state.number
 });
 }
 
 render() {
 return (
  <div>
  <div>{this.state.number}</div>
  <button onClick={()=>{this.handleClick();}}>
   Click
  </button>
  </div>
 );
 }
}

这种方式最大的问题是,每次render调用时,都会重新创建一个事件的回调函数,带来额外的性能开销,当组件的层级越低时,这种开销就越大,因为任何一个上层组件的变化都可能会触发这个组件的render方法。当然,在大多数情况下,这点性能损失是可以不必在意的。这种方式也有一个好处,就是不需要考虑this的指向问题,因为这种写法保证箭头函数中的this指向的总是当前组件。

二、使用组件方法

代码先:

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

 handleClick() {
 this.setState({
  number: ++this.state.number
 });
 }
 
 render() {
 return (
  <div>
  <div>{this.state.number}</div>
  <button onClick={this.handleClick}>
   Click
  </button>
  </div>
 );
 }
}

这种方式的好处是每次render,不会重新创建一个回调函数,没有额外的性能损失。需要注意的是,使用这种方式要在构造函数中为事件回调函数绑定this: this.handleClick = this.handleClick.bind(this) ,否则handleClick中的this是undefined。这是因为ES6 语法的缘故,ES6 的 Class 构造出来的对象上的方法默认不绑定到 this 上,需要我们手动绑定。每次都手动绑定this是不是有点蛋疼?好吧,让我们来看下一种方式。

三、属性初始化语法(property initializer syntax)

使用ES7的 property initializers,代码可以这样写:

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

 handleClick = () => {
 this.setState({
  number: ++this.state.number
 });
 }
 
 render() {
 return (
  <div>
  <div>{this.state.number}</div>
  <button onClick={this.handleClick}>
   Click
  </button>
  </div>
 );
 }
}

哈哈,再也不用手动绑定this了。但是你需要知道,这个特性还处于试验阶段,默认是不支持的。如果你是使用官方脚手架Create React App 创建的应用,那么这个特性是默认支持的。你也可以自行在项目中引入babel的transform-class-properties插件获取这个特性支持。

四、回调函数传参问题

事件的回调函数默认是会被传入一个事件对象Event作为参数的。如果我想传入其他参数给回调函数应该怎么办呢?

使用第一种方式的话很简单,直接传就可以了:

//代码5
class MyComponent extends React.Component {
 constructor(props) {
 super(props);
 this.state = {
  list: [1,2,3,4],
  current: 1
 };
 }
 
 handleClick(item,event) {
 this.setState({
  current: item
 });
 }

 render() {
 return (
  <ul>
  {this.state.list.map(
   (item)=>(
   <li className={this.state.current === item ? 'current':''} 
   onClick={(event) => this.handleClick(item, event)}>{item}
   </li>
   )
  )}
  </ul>
 );
 }
}

使用第二种方式的话,可以把绑定this的操作延迟到render中,在绑定this的同时,绑定额外的参数:

//代码6
class MyComponent extends React.Component {
 constructor(props) {
 super(props);
 this.state = {
  list: [1,2,3,4],
  current: 1
 };
 }
 
 handleClick(item) {
 this.setState({
  current: item
 });
 }

 render() {
 return (
  <ul>
  {this.state.list.map(
   (item)=>(
   <li className={this.state.current === item ? 'current':''} 
   onClick={this.handleClick.bind(this, item)}>{item}
   </li>
   )
  )}
  </ul>
 );
 }
}

使用第三种方式,解决方案和第二种基本一致:

//代码7
class MyComponent extends React.Component {
 constructor(props) {
 super(props);
 this.state = {
  list: [1,2,3,4],
  current: 1
 };
 }
 
 handleClick = (item) => {
 this.setState({
  current: item
 });
 }

 render() {
 return (
  <ul>
  {this.state.list.map(
   (item)=>(
   <li className={this.state.current === item ? 'current':''} 
   onClick={this.handleClick.bind(undefined, item)}>{item}
   </li>
   )
  )}
  </ul>
 );
 }
}

不过这种方式就有点鸡肋了,因为虽然你不需要通过bind函数绑定this,但仍然要使用bind函数来绑定其他参数。

关于事件响应的回调函数,还有一个地方需要注意。不管你在回调函数中有没有显式的声明事件参数Event,React都会把事件Event作为参数传递给回调函数,且参数Event的位置总是在其他自定义参数的后面。例如,在代码6和代码7中,handleClick的参数中虽然没有声明Event参数,但你依然可以通过arguments[1]获取到事件Event对象。

总结

三种绑定事件回调的方式,第一种有额外的性能损失;第二种需要手动绑定this,代码量增多;第三种用到了ES7的特性,目前并非默认支持,需要Babel插件的支持,但是写法最为简洁,也不需要手动绑定this。推荐使用第二种和第三种方式。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JQuery 学习笔记 选择器之一
Jul 23 Javascript
JavaScript中的一些定位属性[图解]
Jul 14 Javascript
基于JQuery的一个简单的鼠标跟随提示效果
Sep 23 Javascript
使用C++为node.js写扩展模块
Apr 22 Javascript
详解js跨域原理以及2种解决方案
Dec 09 Javascript
jQuery实现点击查看大图并以弹框的形式居中
Aug 08 Javascript
通过V8源码看一个关于JS数组排序的诡异问题
Aug 14 Javascript
vue下拉菜单组件(含搜索)的实现代码
Nov 25 Javascript
微信公众平台 客服接口发消息的实现代码(Java接口开发)
Apr 17 Javascript
vue组件库的在线主题编辑器的实现思路
Apr 03 Javascript
JS字符串和数组如何实现相互转化
Jul 02 Javascript
详解在IDEA中将Echarts引入web两种方式(使用js文件和maven的依赖导入)
Jul 11 Javascript
使用AngularJS编写多选按钮选中时触发指定方法的指令代码详解
Jul 24 #Javascript
想用好React的你必须要知道的一些事情
Jul 24 #Javascript
利用node.js实现反向代理的方法详解
Jul 24 #Javascript
Vue2 Vue-cli中使用Typescript的配置详解
Jul 24 #Javascript
mui开发中获取单选按钮、复选框的值(实例讲解)
Jul 24 #Javascript
JavaScript对JSON数据进行排序和搜索
Jul 24 #Javascript
Angular中ng-repeat与ul li的多层嵌套重复问题
Jul 24 #Javascript
You might like
php&amp;java(三)
2006/10/09 PHP
PHP在弹框中获取foreach中遍历的id值并传递给地址栏
2017/06/13 PHP
阿里云的WindowsServer2016上部署php+apache
2018/07/17 PHP
PHP连接SQL Server的方法分析【基于thinkPHP5.1框架】
2019/05/06 PHP
Vagrant(WSL)+PHPStorm+Xdebu 断点调试环境搭建
2019/12/13 PHP
用javascript父窗口控制只弹出一个子窗口
2007/04/10 Javascript
鼠标经过tr时,改变tr当前背景颜色
2014/01/13 Javascript
Array栈方法和队列方法的特点说明
2014/01/24 Javascript
javascript中解析四则运算表达式的算法和示例
2014/08/11 Javascript
jQuery关键词说明插件cluetip使用指南
2015/04/21 Javascript
javascript禁止访客复制网页内容的实现代码
2015/08/05 Javascript
解决jQuery上传插件Uploadify出现Http Error 302错误的方法
2015/12/18 Javascript
JavaScript学习笔记之取数组中最大值和最小值
2016/03/23 Javascript
Bootstrap整体框架之JavaScript插件架构
2016/12/15 Javascript
jquery Easyui Datagrid实现批量操作(编辑,删除,添加)
2017/02/20 Javascript
vue音乐播放器插件vue-aplayer的配置及其使用实例详解
2017/07/10 Javascript
js实现首屏延迟加载实现方法 js实现多屏单张图片延迟加载效果
2017/07/17 Javascript
js生成word中图片处理方法
2018/01/06 Javascript
详解React-Router中Url参数改变页面不刷新的解决办法
2018/05/08 Javascript
js将日期格式转换为YYYY-MM-DD HH:MM:SS
2020/09/18 Javascript
python 中文乱码问题深入分析
2011/03/13 Python
python杀死一个线程的方法
2015/09/06 Python
对python中两种列表元素去重函数性能的比较方法
2018/06/29 Python
使用Python实现微信提醒备忘录功能
2018/12/04 Python
python 字符串常用函数详解
2019/09/11 Python
自适应线性神经网络Adaline的python实现详解
2019/09/30 Python
django使用JWT保存用户登录信息
2020/04/22 Python
Python函数参数定义及传递方式解析
2020/06/10 Python
python中tab键是什么意思
2020/06/18 Python
网购亚洲时装、美容产品和生活百货:YesStyle
2016/09/15 全球购物
给客户的道歉信
2014/01/13 职场文书
创业者迈进成功第一步:如何写创业计划书?
2014/03/22 职场文书
求职信模板
2014/05/23 职场文书
拉拉队口号
2014/06/16 职场文书
单位政审意见范文
2015/06/04 职场文书
2019年手机市场的调研报告2篇
2019/10/10 职场文书