引言
Airbnb 的编程规范里提到,“当在 render() 里使用事件处理方法时,提前在构造函数里把 this 绑定上去.”
为什么? 在每次 render 过程中,再调用 bind 都会新建一个新的函数,浪费资源.
// bad
class extends React.Component {
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv.bind(this)} />;
}
}
// good
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return <div onClick={this.onClickDiv} />;
}
}
认识bind函数
bind函数的具体功能与apply,call函数相似,都是改变函数体内的this对象,也就是扩充函数作用域。在MDN中是这样介绍bind的:
bind()方法创建一个新的函数, 当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列。
由上可知,bind函数和apply、call函数不同在于,bind函数执行后返回的是一个绑定了this对象的函数,而apply和call函数是直接执行。
我们来看一个简单的例子用来说明apply,call和bind的区别:
var x = 'out'
var a = {
x:'inner',
func:function(){
console.info('Now the environment is',this.x)
}
}
var b = a.func// inner
b.apply(a) // Now the environment is inner
b.call(a) // Now the environment is inner
b.bind(a) // No output because the bind function returns a new function
typeof b.bind(a) === 'function' // true
b.bind(a)() // Now the environment isinner
bind函数可以异步执行,这是它区别于apply和bind的主要地方。
React最佳实践
React.Component:由于使用了 ES6的原因,属性并不会自动绑定到 React 类的实例上。
import React from 'react';
class TodoItem extends React.Component{
constructor(props){
super(props);
}
handleClick(){
console.log(this); // null
}
handleFocus(){ // manually bind this
console.log(this); // React Component Instance
}
handleBlur: ()=>{ // use arrow function
console.log(this); // React Component Instance
}
render(){
return <input onClick={this.handleClick}
onFocus={this.handleFocus.bind(this)}
onBlur={this.handleBlur}/>
}
}
前面提到,在每次 render 过程中,再调用 bind 都会新建一个新的函数,浪费资源.我们可以在 constructor 中来改变 this.handleClick 执行的上下文,这应该是相对上面一种来说更好的办法。另外还有一个好处就是,万一我们需要改变语法结构,这种方式完全不需要去改动 JSX 的部分:
import React from 'react';
class Contacts extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log(this); // React Component instance
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
}
export default Contacts;
参考资料
1、思否:React.createClass和extends Component的区别
2、掘金:详解bind
3、github:Airbnb React/JSX 编码规范