最近在React官网学习Handling Events这一章时,有一处不是很明白。代码如下:

class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = {isToggleOn: true}; // This binding is necessary to make `this` work in the callback
this.handleClick = this.handleClick.bind(this);
} handleClick() {
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}));
} render() {
return (
<button onClick={this.handleClick}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
} ReactDOM.render(
<Toggle />,
document.getElementById('root')
);

注意到在Toggle类的构造函数constructor类中,有一句注释:“This binding is necessary to make `this` work in the callback”,即在构造函数中,利用Function.bind()函数将类中已有的handleClick函数再次绑定了一下this。对于这个做法,官网给出的注释是:

这段话说了看似说了很多,其实就两点:

1.如果你不绑定this.handleClick方法,那么在事件发生并且精确调用这个方法时,方法内部的this会丢失指向。
2.这不是React的原因,这是JavaScript中本来就有的。如果你传递一个函数名给一个变量,然后通过在变量后加括号()来调用这个方法,
 此时方法内部的this的指向就会丢失

这一段点明了为什么要在构造函数中绑定this,因为JavaScript中确实有这么一个陷阱。具体是怎么样的呢?我进行了一下测试:

let obj = {
tmp:'Yes!',
testLog:function(){
console.log(this.tmp);
}
};
obj.testLog();

为了便于为学习ES6的童鞋理解以及说明这是JavaScript中的陷阱而非React所特有,这里使用字面量表达式声明对象。

经过测试,这样使用obj中的testLog方法时,this指向obj,能够正常输出tmp属性:

现在修改一下代码:

let obj = {
tmp:'Yes!',
testLog:function(){
console.log(this.tmp);
}
};
let tmpLog = obj.testLog;
tmpLog();

注意到现在没有直接调用obj对象中的testLog方法,而是使用了一个中间变量tmpLog过渡,当使用括号()调用该方法时,方法中的this丢失了指向,会指向window,进而window.tmp未定义就是undefined:

说了这么多,跟React事件处理函数的绑定有什么关系呢?

前面讲过,React跟原生JavaScript的事件绑定区别有两点,其中第二点就是:

即在React(或者说JSX)中,传递的事件参数不是一个字符串,而是一个实实在在的函数:

这样说,React中的事件名(上图中的onClick)就是我所举例子中的中间变量,React在事件发生时调用onClick,由于onClick只是中间变量,所以处理函数中的this指向会丢失,为了解决这个问题,我们需要在实例化对象的时候,需要在构造函数中绑定this,使得无论事件处理函数如何传递,它的this的指向都是固定的,固定指向我们所实例化的对象。

这个JavaScript陷阱是对我之前文章关于JavaScript中的this的一个很好的补充。

另外,在后续学习当中,发现可能存在其他原因,具体参见阮一峰的博客:ES6 class语法中this的指向

为什么React事件处理函数必须使用Function.bind()绑定this?的更多相关文章

  1. React事件处理函数传参问题

    React事件处理函数参数 HTML标签与React 组件是不同的,事件对象e是HTML标签元素的,组件没有的.

  2. (转)React事件处理函数必须使用bind(this)的原因

    1.JavaScript自身特性说明如果传递一个函数名给一个变量,之后通过函数名()的方式进行调用,在方法内部如果使用this则this的指向会丢失.示例代码:首先我们创建test对象并直接调用方法 ...

  3. react事件处理函数中绑定this的bind()函数

    问题引入 import React, { Component } from 'react'; import { Text, View } from 'react-native'; export def ...

  4. React事件处理函数的bind复用和name复用

    一.bind复用 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=&qu ...

  5. React 事件处理函数

    触摸事件:onTouchCancel\onTouchEnd\onTouchMove\onTouchStart (只会在移动设备上接受) 键盘事件:onKeyDown\onKeyPress\onKeyU ...

  6. React 学习(三) ---- state 和 事件处理函数

    在上两节中,我们讲述了props, 组件使用props进行渲染,但是这是一次性的, props渲染完成之后就不做任何事情了,但是现实中却不是这样的,当我们点击购物车上的加减按钮时,数量会自动加1或减1 ...

  7. Jquery动态绑定事件处理函数 bind / on / delegate

    1.bind方法绑定的事件处理函数不会应用到后来添加到DOM中的新元素.比如你在用bind给页面元素绑定事件之后,又新添加了一些与之前绑定过事件的元素一样的DOM元素,但是这些事件并不能在新的DOM元 ...

  8. React事件处理、收集表单数据、高阶函数

    3.React事件处理.收集表单数据.高阶函数 3.1事件处理 class Demo extends React.Component { /* 1. 通过onXxx属性指定事件处理函数(注意大小写) ...

  9. C++ 类的成员函数指针 ( function/bind )

    这个概念主要用在C++中去实现"委托"的特性. 但现在C++11 中有了 更好用的function/bind 功能.但对于类的成员函数指针的概念我们还是应该掌握的. 类函数指针 就 ...

随机推荐

  1. Linux下LDAP统一认证解决方案

    Linux下LDAP统一认证解决方案 --http://www.cangfengzhe.com/wangluoanquan/3.html 转自:http://www.cnblogs.com/MYSQL ...

  2. VS2013安装MVC5

    打开VS 选择  .net 4.5 创建项目 右击项目 选择管理NuGet 输入Microsoft.AspNet.Mvc -Version 5.0.0 安装最新版本的MVC5

  3. 【oneday_onepage】——How to stretch the life of your SSD storage

    How to stretch the life of your SSD storage July 18, 2013, 9:06 PM — Once a PC enthusiast's dream st ...

  4. 红楼梦人物关系图,一代大师成绝响,下回分解待何人,kindle读书摘要

      人物关系图: https://www.cnblogs.com/images/cnblogs_com/elesos/1120632/o_2033091006.jpg 红楼梦 (古典名著普及文库) ( ...

  5. android适配pad和部分手机底部虚拟按键+沉浸式状态栏

    在使用沉浸式状态栏设置界面全屏时发现pad和部分手机(华为和魅族系统自带)屏幕底部会带有虚拟按键,遮挡住界面本身的一部分. 为了设置隐藏,在网上找了一些方法,设置Activity主题再在布局加fits ...

  6. Android跳转系统界面_大全集

    1.跳转Setting应用列表(所有应用) Intent intent = new Intent(Settings.ACTION_MANAGE_ALL_APPLICATIONS_SETTINGS); ...

  7. linux 卸载mysql

    RPM包安装方式的MySQL卸载 1: 检查是否安装了MySQL组件. [root@DB-Server init.d]# rpm -qa | grep -i mysql   MySQL-devel-5 ...

  8. 【转】一个小妙招能让你在服装上省下好多rmb

    朋友们,你们仔细算过自己每年在淘宝上买衣服消费了多少rmb吗?100?1000?10000?甚至更多? 朋友们,你知道淘宝上大多数店铺的衣服是哪里来的吗? 朋友们,你知道怎么在这上面能节省更多的mon ...

  9. window.showModalDialog乱码(完美)解决方案

    关于jsp弹出jsp页面传参数中文乱码的问题解决: 弹出方式--window.showModalDialog(requestURL,null,strFeatureInfo); 乱码原因:url传递方式 ...

  10. e859. 将键盘事件和字符串对应

    The KeyStroke.toString() method does not return a string that can be parsed by KeyStroke.getKeyStrok ...