Airbnb React/JSX 编码规范之Methods函数

750 阅读2分钟

引言


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 编码规范