published on
tags: react

React 绑定this 三种方式对比

在react中,在组件事件上绑定this通常有三种写法

  1. inline function
   <Button onClick={() => this.handleChange></Button>
  1. class properties
   class A {
     handleChange = () => {
       coneole.log()
     }
   }
  1. bind
   class B {
     constructor() {
       this.handleChange = this.handleChange.bind(this)
     }
   
     handleChange() {
       console.log()
     }
   }

哪种方法相较而言更适合呢,这个在React的Github Issue里都已经有过多次讨论。https://github.com/facebook/react/issues/9851 根据Dan Abramov的说法,两者基本一致,但在Facebook内部使用的是第二种方法(calss properties)。

虽然两者基本一致,但是肯定有细微的差别,第二种方法因为目前还不是ES的正式语法,所有需要使用babel插件babel-plugin-transform-class-properties进行转义,下面是babel转换A和B的代码

var A = function A() {
  _classCallCheck(this, A);

  this.handleChange = function () {
    coneole.log();
  };
};


var B = function () {
  function B() {
    _classCallCheck(this, B);

    this.handleChange = this.handleChange.bind(this);
  }

  _createClass(B, [{
    key: "handleChange",
    value: function handleChange() {
      console.log();
    }
  }]);

  return B;
}();

我们在这里分别实例化上面代码中的A和B并打印这两个实例,如下图 image

使用class properties语法的A实例handleChange只存在实例上,使用bind绑定this的在实例和原型上分别存在handleChange方法, 看上去似乎前者的开销比后者小。

性能方面,可以做个测试进行对比,https://jsperf.com/arrow-function-vs-bound-function-with-100-instances。

image

op/s的测试结果显示bind方式比class properties在性能方面更加优秀,但是没有超过50%,优势不是很大。

但是如果如果在constructor中显式bind this,那么在组件中如果含有大量事件,是会拖慢组件初始化速度,是你的应用程序变慢。

有一种说法是如果你的组件性能受到的影响微乎其微,不要过早的进行优化,因为可能带来副作用,只有在观测到时在进行优化。

第一种内联函数方式是最不被人接受的,因为垃圾回收机制和在使用pureComponent ,在组件中内联的使用一个对象会使Shallow Compare 失效,因为总会产生一个新的对象,是严格不相等的,从而引起重新渲染。

但是有中情况是需要从外部传递参数给事件函数,这种情况下我们不得不使用内联函数,有一种解决方案是讲数据传递到html的表单元素上,通过e.target.value获取。

class C {
    handleClick = (e) => {
        const id = e.target.value
        // do something
    }
    
    render() {
        const id = {this.state}
        return (<button value={id} onClick={this.handleClick}>提交</button>)
    }
}

还有一种解决方案是提取子组件,具体可以看这篇文章https://medium.freecodecamp.org/react-pattern-extract-child-components-to-avoid-binding-e3ad8310725e 但两者都有相应局限性,不是广泛的适用于所有场景。

如果你的组件不是追求极限性能优化或者是拥有超多的子组件,不论采用2和3哪种方式,都是可以的,主要还是看团队规范。