代码如下:

class test extends Component {
constructor(props) {
super(props);
this.state = {
liked: false
};
}
handleClick(event) {
this.setState({liked: !this.state.liked});
}
render() {
var text = this.state.liked ? '喜欢' : '不喜欢';
return (
<div onClick={this.handleClick}>
你<b>{text}</b>我。点我切换状态。
</div>
);
} }
export default test;

可以正常展示页面:

但是按钮一按就会报错。

为什么会出现这种情况呢?

因为点击按钮时,到了handleClick()方法中的this已经不是组件里的this了。

第一种解决方法是:手动绑定this。将

constructor(props) {
super(props);
this.state = {
liked: false
};
}

改为

constructor(props) {
super(props);
this.state = {
liked: false
};
this.handleClick = this.handleClick.bind(this);//手动绑定
}

第二种解决办法是:将

handleClick(event) {
this.setState({liked: !this.state.liked});
}

改为

handleClick= (e) => {
this.setState({liked: !this.state.liked});
}

这种解决方法之所以能解决问题,就引申到了另外一个问题:函数作为React组件的方法时, 箭头函数和普通函数的区别是什么?

举个例子:下面2个a的定义有什么区别?

class App extends Component {
a() {
console.log(1)
} a = () => {
console.log(1)
}
}

第一个 a 不必说,是原型方法的定义。宽松模式下对应 ES5 就是

App.prototype.a = function() {}
第二个是 Stage 2 Public Class Fields 里面的写法,babel 下需要用 Class properties transform Plugin 进行转义。相当于:
class App extends Component {
constructor (...args) {
super(...args)
this.a = () => {
console.log(1)
}
}
}

为什么需要第二种写法?

在 React 里面,要将类的原型方法通过 props 传给子组件,传统写法需要 bind(this),否则方法执行时 this 会找不到:

<button onClick={this.handleClick.bind(this)}></button>

或者

<button onClick={(e) => this.handleClick(e)}></button>

这种写法难看不说,还会对 React 组件的 shouldComponentUpdate 优化造成影响。

这是因为 React 提供了 shouldComponentUpdate 让开发者能够控制避免不必要的 render,还提供了在 shouldComponentUpdate 自动进行 Shallow Compare 的 React.PureComponent, 继承自 PureComponent 的组件只要 props 和 state 中的值不变,组件就不会重新 render。

然而如果用了 bind this,每次父组件渲染,传给子组件的 props.onClick 都会变,PureComponent 的 Shallow Compare 基本上就失效了,除非你手动实现 shouldComponentUpdate.

使用 Public Class Fields 的这种写法,就解决了这个问题。另外还有其他若干种办法,比如先定义原型方法,然后在 constructor 里面 bind 一遍;或者使用 decorator 进行 bind 等:

class A {
constructor() {
this.a = this.a.bind(this)
} a() {} // or
@bindthis
b() {}
}

而箭头函数除了代码少。与普通函数最大的不同就是:this是由声明该函数时候定义的,一般是隐性定义为声明该函数时的作用域this。

var a = ()=>{
console.log(this)
}
//等同于
var a = function(){
console.log(this)
}.bind(this); a(); //Window
var b = function(){
console.log(this)
};
b(); //Window
var obj = { a,b };
obj.a(); //Window
obj.b(); //obj

箭头函数最大的作用是使得this从正常情况下的动态作用域(根据运行位置确定值)变成了静态作用域(根据定义位置确定值,也就是词法作用域)。
若想了解得更详细,可以去阅读官方文档: https://reactjs.org/docs/handling-events.html

react报错 TypeError: Cannot read property 'setState' of undefined的更多相关文章

  1. VUE.JS 使用axios数据请求时数据绑定时 报错 TypeError: Cannot set property 'xxxx' of undefined 的解决办法

    正常情况下在data里面都有做了定义 在函数里面进行赋值 这时候你运行时会发现,数据可以请求到,但是会报错 TypeError: Cannot set property 'listgroup' of ...

  2. Node中使用MySQL报错:TypeError: Cannot read property 'query' of undefined

    Node中使用MySQL报错: TypeError: Cannot read property 'query' of undefined at /Users/sipeng/Desktop/彭思/201 ...

  3. 使用webpack命令打包时,报错TypeError: Cannot read property 'presetToOptions' of undefined的解决办法

    我只安装了webpack,没有安装webpack-cli,第一次输入webpack打包时,提示 One CLI for webpack must be installed. These are rec ...

  4. vue表单校验提交报错TypeError: Cannot read property 'validate' of undefined

    TypeError: Cannot read property 'validate' of undefined at VueComponent.submitForm (plat_users.html: ...

  5. vue报错TypeError: Cannot read property 'protocol' of undefined

    错误信息如下所示: isURLSameOrigin.js?3934:57 Uncaught (in promise) TypeError: Cannot read property 'protocol ...

  6. vue报错TypeError: Cannot read property '$createElement' of undefined

    报错截图: 这个错误就是路由上的component写成了components

  7. Node.js报错TypeError: Cannot read property 'isDirectory' of undefined

    截图如下: 原因如下:记住"./uploads" 后要加一个/ fs.stat("./uploads/" + files[i], function(err, s ...

  8. VUE - 使用axios数据请求时数据绑定时 报错 TypeError: Cannot set property 'xxxx' of undefined 的解决办法

     created() {     var that=this     axios.get('http://jsonplaceholder.typicode.com/todos')     .then( ...

  9. JS报错:Cannot read property 'type' of undefined

    在做图片上传功能的时候,遇到了JS无法识别图片type的问题,在使用过程中是没有问题的,但是不知道为什么浏览器的Console报这个错误: Uncaught TypeError: Cannot rea ...

随机推荐

  1. JavaSwing 船只停靠管理可视化(四)

    JavaSwing 船只停靠管理可视化(一) JavaSwing 船只停靠管理可视化(二) JavaSwing 船只停靠管理可视化(三) JavaSwing 船只停靠管理可视化(四) JavaSwin ...

  2. hadoop3.2+Centos7+5个节点主从模式配置

    准备工作: hadoop3.2.0+jdk1.8+centos7+zookeeper3.4.5 以上是我搭建集群使用的基础包 一.环境准备 master1 master2 slave1 slave2 ...

  3. UNION An Unreferenced Metric for Evaluating Open-ended Story Generation精读

    UNION An Unreferenced Metric for Evaluating Open-ended Story Generation精读 UNION: 一种评估开放故事生成无参考文本依赖me ...

  4. 技术基础 | 监测Apache Cassandra的简明方式——MCAC

    点击这里在GitHub上访问我们,以便深入了解DataStax的开源项目--Apache Cassandra指标收集器(Metric Collector for Apache Cassandra, o ...

  5. linux下用户管理命令、用户组管理命令

    useradd 添加新用户 1.基本语法 useradd 用户名                   (功能描述:添加新用户) useradd -g 组名 用户名      (功能描述:添加新用户到某 ...

  6. Spring Security OAuth2.0认证授权一:框架搭建和认证测试

    一.OAuth2.0介绍 OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不 需要将用户名和密码提供给第三方应用或分享他们数据的所有内容. 1.s ...

  7. 申请免费域名并配置DNS解析及CDN加速

    标题: 申请免费域名并配置DNS解析及CDN加速 作者: 梦幻之心星 sky-seeker@qq.com 标签: [#申请,#免费,#域名,#DNS解析,#CDN加速,#子域名] 目录: [网站] 日 ...

  8. Ubuntu无法ssh远程连接问题 (转)

    [系统]Ubuntu 12.04 server [问题描述]新安装的Ubuntu系统无法直接通过ssh远程连接. [解决办法] 新安装的Ubuntu系统并未安装ssh-server服务,需要自行安装, ...

  9. java的重载与重写

    原文链接http://zhhll.icu/2020/11/11/java%E5%9F%BA%E7%A1%80/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1/%E9%87%8 ...

  10. C/C++内存对齐详解

    1.什么是内存对齐 还是用一个例子带出这个问题,看下面的小程序,理论上,32位系统下,int占4byte,char占一个byte,那么将它们放到一个结构体中应该占4+1=5byte:但是实际上,通过运 ...