结合React和es6中Class类, 目的是加深理解react框架中 this 上下文指向问题,记录笔记;
那么我们为什么需要在react里bind(this)呢? 简单来说,就是react在调用render方法的时候, 会先把render里的方法赋值给一个变量(比如变量foo,onClick),然后再执行foo(),onClick()。 具体来说,以典型的绑定点击事件为例
<div onClick={this.clickHandler}>测试</div>
react构建虚拟DOM的时候,会把this.clickHandler先赋值给一个变量(react 点击事件是 onClick)。我们假设是变量clickFunc = this.clickHandler; 然后,把虚拟DOM渲染成真实DOM的时候,会把onClick属性值替换成onclick,并给onclick赋值clickFunc
在复杂的情况中,可能存在多次传递,如果不进行bind,那么this的指向是一定会丢失的。
方法一:React.createClass 自动绑定
React 中创建组件的方式已经很多,比较古老的诸如 React.createClass 应该很多人并不陌生。当然,从 React 0.13 开始,可以使用 ES6 Class 代替 React.createClass 了,这应该是今后推荐的方法。
但是需要知道,React.createClass 创建的组件,可以自动绑定 this。也就是说,this 这个关键字会自动绑定在组件实例上面。
// This magically works with React.createClass
// because `this` is bound for you.
onClick = {this.handleChange}
当然,对于组件的创建,官方已经推荐使用 class 声明组件或使用 functional 无状态组件;
方法二:渲染时绑定
我们假定所有的组件都采取 ES6 class 方式声明。这种情况下,this 无法自动绑定。一个常见的解决方案便是:
onClick = {this.handleChange.bind(this)}
这种方法简明扼要,但是有一个潜在的性能问题:当组件每次重新渲染时,都会有一个新的函数创建。 这听上去貌似是一个很大的问题,但是其实在真正的开发场景中,由此引发的性能问题往往不值一提(除非是大型组件消费类应用或游戏)。
方法三:箭头函数绑定
这种方法其实和第二种类似,都是用 es6 Class定义,我们可以隐式绑定 this:
//普通函数
handleClick(){
console.log('handleClick--实例',this);
};
render () {
return (
<div>
<Button type="primary" onClick={ ()=>{ this.handleClick() } }>修改 username </Button>
</div>
)
}
当然,也与第二种方法一样,它同样存在潜在的性能问题。 下面将要介绍的两种方法,可以有效规避不必要的性能消耗.
方法四:Constructor 内绑定
constructor 方法是class类的默认构造方法,默认返回实例对象,通过new命令生成对象实例时,自动调用该方法。es6 阮一峰 Class
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
这种方式往往被推荐为“最佳实践”.
但是就个人习惯而言,我认为与前两种方法相比:
constructor 内绑定,在可读性和可维护性上也有些欠缺。同时,我们知道在 constructor 声明的方法不会存在实例的原型prototype上,而属于实例本身的方法。每个实例都有同样一个 handleChange,这本身也是一种重复和浪费。
方法五:Class 属性中 自定义的方法用箭头函数,需要安装 plugin:babel-plugin-transform-class-properties
//箭头函数
handleClick = () => {
console.log('handleClick--实例',this);
// call this function from render
// and this.whatever in here works fine.
};
render () {
return (
<div>
<Button type="primary" onClick={ this.handleClick }>修改 username </Button>
</div>
)
}
我们来总结一下这种方式的优点:
- 使用箭头函数,有效绑定了 this;
- 没有第二种方法和第三种方法的潜在性能问题;
- 避免了方法四的组件实例重复问题;
- 我们可以直接从 ES5 createClass 重构得来。
感谢参考链接