Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React 绑定this 三种方式对比 #1

Open
TopGrd opened this issue Aug 22, 2018 · 1 comment
Open

React 绑定this 三种方式对比 #1

TopGrd opened this issue Aug 22, 2018 · 1 comment
Labels

Comments

@TopGrd
Copy link
Owner

TopGrd commented Aug 22, 2018

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

  1. inline function

    <Button onClick={() => this.handleChange></Button>
  2. class properties

    class A {
      handleChange = () => {
        coneole.log()
      }
    }
  3. bind

    class B {
      constructor() {
        this.handleChange = this.handleChange.bind(this)
      }
    
      handleChange() {
        console.log()
      }
    }

哪种方法相较而言更适合呢,这个在React的Github Issue里都已经有过多次讨论。facebook/react#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哪种方式,都是可以的,主要还是看团队规范。

@TopGrd TopGrd added the react label Aug 22, 2018
@TopGrd
Copy link
Owner Author

TopGrd commented Jun 10, 2019

关于性能:为什么 bind 比箭头函数性能好?
因为实例中,prototype的函数是共享的,如果我们有N个组件,他们共享同样的方法,那么click时候,会调用同一个prototype。由于我们在原型中多次调用相同的方法,因此JavaScript引擎可以对其进行优化。
相反箭头函数的话,N个组件会创建N个不同的方法,如果我们点击N个component,会调用不同的函数。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant