react报错 TypeError: Cannot read property 'setState' of undefined
代码如下:
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