在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 相关文章推荐
发布一个高效的JavaScript分析、压缩工具 JavaScript Analyser
Nov 30 Javascript
几个常用的JavaScript字符串处理函数 - split()、join()、substring()和indexOf()
Jun 02 Javascript
在一个浏览器里呈现所有浏览器测试结果的前端测试工具的思路
Mar 02 Javascript
基于Jquery实现表格动态分页实现代码
Jun 21 Javascript
在javascript中执行任意html代码的方法示例解读
Dec 25 Javascript
JavaScript利用构造函数和原型的方式模拟C#类的功能
Mar 06 Javascript
JS未跨域操作iframe里的DOM
Jun 01 Javascript
AngularJS实现在ng-Options加上index的解决方法
Nov 03 Javascript
Angular ui.bootstrap.pagination分页
Jan 20 Javascript
js中Number数字数值运算后值不对的解决方法
Feb 28 Javascript
Vue axios全局拦截 get请求、post请求、配置请求的实例代码
Nov 28 Javascript
layui 监听select选择 获取当前select的ID名称方法
Sep 24 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获取日期对应星期、一周日期、星期开始与结束日期的方法
2018/06/22 PHP
PHP 进程池与轮询调度算法实现多任务的示例代码
2019/11/26 PHP
dtree 网页树状菜单及传递对象集合到js内,动态生成节点
2012/04/14 Javascript
Javascript中判断变量是数组还是对象(array还是object)
2013/08/14 Javascript
EasyUI实现二级页面的内容勾选的方法
2015/03/01 Javascript
javascript用函数实现对象的方法
2015/05/14 Javascript
基于Node.js的强大爬虫 能直接发布抓取的文章哦
2016/01/10 Javascript
Nodejs多站点切换Htpps协议详解及简单实例
2017/02/23 NodeJs
JS实现异步上传压缩图片
2017/04/22 Javascript
node中koa中间件机制详解
2017/08/22 Javascript
利用vue + koa2 + mockjs模拟数据的方法教程
2017/11/22 Javascript
用react-redux实现react组件之间数据共享的方法
2018/06/08 Javascript
React事件处理的机制及原理
2018/12/03 Javascript
js实现div色块拖动录制
2020/01/16 Javascript
Vue-cli3生成的Vue项目加载Mxgraph方法示例
2020/05/31 Javascript
详解Python编程中对Monkey Patch猴子补丁开发方式的运用
2016/05/27 Python
Python读取本地文件并解析网页元素的方法
2018/05/21 Python
详解python算法之冒泡排序
2019/03/05 Python
django项目用higcharts统计最近七天文章点击量
2019/08/17 Python
OpenCV 使用imread()函数读取图片的六种正确姿势
2020/07/09 Python
实例代码讲解Python 线程池
2020/08/24 Python
html5摇一摇代码优化包括DeviceMotionEvent等等
2014/09/01 HTML / CSS
HTML5 拖放(Drag 和 Drop)详解与实例代码
2017/09/14 HTML / CSS
Urban Outfitters美国官网:美国生活方式品牌
2016/08/26 全球购物
Anthropologie英国:美国家喻户晓的休闲服装和家居产品品牌
2018/12/05 全球购物
Expedia西班牙:预订酒店、机票、旅行和廉价度假套餐
2019/04/10 全球购物
工程业务员岗位职责
2013/12/31 职场文书
大学生学期自我鉴定
2014/03/19 职场文书
篮球比赛拉拉队口号
2014/06/10 职场文书
合作协议书范文
2014/08/20 职场文书
仓库管理员岗位职责
2015/02/03 职场文书
2015年五四青年节演讲稿
2015/03/18 职场文书
听证通知书
2015/04/24 职场文书
单位接收证明格式
2015/06/18 职场文书
2016年领导干部正风肃纪心得体会
2015/10/09 职场文书
光之国的四大叛徒:第一贝利亚导致宇宙毁灭,赛文奥特曼在榜
2022/03/18 日漫