class App extends React.Component {
handleClick2;
constructor(props) {
super(props);
this.state = {
count: 1,
title: 'react function'
};
this.handleClick2 = this.handleClick1.bind(this);
}
handleClick1() {
this.setState({
num: this.state.count + 1,
})
}
handleClick3 = () => {
this.setState({
num: this.state.count + 1,
})
};
render() {
return (<div>
<h2>Ann, {this.state.count}</h2>
<button onClick={this.handleClick2}>btn1</button>
<button onClick={this.handleClick1.bind(this)}>btn2</button>
<button onClick={() => this.handleClick1()}>btn3</button>
<button onClick={this.handleClick3}>btn4</button>
</div>)
}
}
- 第一种是在构造函数中绑定 this:那么每次父组件刷新的时候,如果传递给子组件其他的 props 值不变,那么子组件就不会刷新;
- 第二种是在 render() 函数里面绑定 this:因为 bind 函数会返回一个新的函数,所以每次父组件刷新时,都会重新生成一个函数,即使父组件传递给子组件其他的 props 值不变,子组件每次都会刷新;
- 第三种是使用箭头函数:父组件刷新的时候,即使两个箭头函数的函数体是一样的,都会生成一个新的箭头函数,所以子组件每次都会刷新;
- 第四种是使用类的静态属性:原理和第一种方法差不多,比第一种更简洁
综上所述,如果不注意的话,很容易写成第三种写法,导致性能上有所损耗。
为什么要绑定this
js里面的this绑定是代码执行的时候进行绑定的,而不是编写的时候,所以this的指向取决于函数调用时的各种条件。
var a = "foo";
function foo(){
console.log(this.a);
}
foo(); // "foo"
在浏览器环境中,单独运行的函数,也就是没有跟任何对象产生关系的情况下执行该函数,此时的this会指向window对象,在Node环境中会指向global对象。所以上面代码中this指向了window,然后调用了找到了window中的变量a。
- 严格模式下
var a = "foo";
function foo(){
"use strict";
console.log(this.a);
}
foo(); // TypeError:this is undefined
这里关于默认绑定的另一种情况需要注意:在严格模式下,全局对象将无法使用默认绑定,因此this会绑定到undefined。在ES6的class中,也会绑定到undefined
- 在class中
class A {
constructor(){
this.aa = 1;
}
hello(){
console.log(this.aa);
}
hello2() {
(function(){
console.log(this.aa);
})();
}
}
const a = new A();
a.hello(); // 1
a.hello2(); // Uncaught TypeError: Cannot read property 'aa' of undefined
类的方法内部如果含有 this, 它将默认指向类的实例.但是如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,所以会报错
在react中
class View extends React.Component {
constructor(props){
super(props);
this.state={
}
}
handleClick(e) {
console.log(e);
}
render(){
return (
<a onClick={this.handleClick}>click me</a>
);
}
}
主要将注意力放在JSX的语法中,其中点击的回调方法对函数进行了this的绑定。但是前面a.hello();不是可以正常输出么?正常绑定了this么?为什么这里还需要进行绑定?因为使用了jsx语法.
jsx
想要搞清楚为什么需要绑定this,就需要搞清楚JSX到底是一个什么东西。我们看react官方的描述:
本质上来讲,JSX 只是为 React.createElement(component, props, ...children) 方法提供的语法糖。比如下面的代码:
<MyButton color="blue" type="primary">
Click Me
</MyButton>
编译为:
React.createElement(
MyButton,
{color: 'blue', type: "primary"},
'Click Me'
)
如果没有子代,你还可以使用自闭合标签,比如:
<div className="div" />
编译为:
React.createElement(
'div',
{className: 'div'},
null
)
去JSX后的react组件
class View extends React.Component {
constructor(props){
super(props);
}
handleClick(e) {
console.log(e);
}
render(){
return React.createElement(
"a",
{ onClick: this.handleClick},
"click me"
);
}
}
这时this.handleClick这里的this就会像a.hello2的里面this绑定一样,this会默认绑定,但是又是在ES6的class中(默认严格模式),所以this绑定了undefined,所以为了能在回调函数中使用的this指向当前组件实例需要手动绑定this