我应该在哪里绑定React组件中的方法?

时间:2018-09-05 18:15:27

标签: javascript reactjs ecmascript-6 arrow-functions

我现在学习React,并且注意到很多人将其方法绑定到构造函数中。

赞:

class MyComponent extends React.Component {
  constructor() {
    super();
    this.myMethod = this.myMethod.bind(this);
  }

  render() {
    <button onClick={this.myMethod}>Click me</button>
  }

  myMethod() {
    // do something
  }
}

但是我习惯于写这样的东西:

render() {
    <button onClick={this.myMethod.bind(this)}>Click me</button>
}

几个人告诉我,使用第二种方法是不好的体验。

那么您能告诉我第一方法和第二方法之间的区别吗?任何利弊?或性能问题?

6 个答案:

答案 0 :(得分:1)

你是对的,别人告诉你的也是对的。

我们鼓励您在构造函数中进行绑定,因为每个组件只对构造函数进行一次调用,因此,如果在构造函数中进行绑定,则它只会在Webpack bundle.js文件中创建一次新的对象/函数,因此影响不大

不建议您直接在render中进行绑定,因为组件会出于多种原因进行渲染,例如执行setState时,组件收到新的props时,因此组件将渲染很多次。因此,由于您每次在组件渲染时都直接绑定在render中,因此每次在Webpack bundle.js中都会创建一个新函数,并且捆绑文件的大小会增加,并且当您的应用程序包含数千个组件并且如果您直接在其中绑定时,这会影响性能。在每个组件中渲染。

因此,建议您仅在构造函数中进行绑定。希望能澄清

答案 1 :(得分:1)

您应该仅在构造函数中进行绑定,因为第二种方法将在每次渲染时创建一个新函数。

但是有一种更好的方法来避免绑定。使用箭头功能。

class MyComponent extends React.Component {
  constructor() {
    super();
  }

  render() {
    <button onClick={this.myMethod}>Click me</button>
  }

  myMethod = ()=> {
    // do something
  }
}

让我们看看Redux Dan Abramov thinks about bind vs arrow functions-的创建者

Question

  

在性能方面,使用箭头之间有什么区别   功能和使用es6类时手动绑定?使用箭头   函数的方法不在类原型上,它将在   仅类实例。使用bind将方法附加到类上   原型。听起来像手动绑定将具有更好的性能,   这是否意味着我们应该考虑使用bind而不是arrow   类方法的功能?

     

任何建议或评论都非常感谢!

     

因此,在性能方面,您是否建议使用

     

class MyComponent扩展了React.Component {构造函数(props){       超级(道具)}

     

methodA =()=> {...}}

     

     

class MyComponent扩展了React.Component {构造函数(props){       超级(道具)       this.methodA = this.methodA.bind(this)}

     

methodA(){...}}

Answer

  

这两种编写方式是等效的。 (第二个是   编译为第一个。)

     

使用bind将方法附加到类原型上。

     

在您的示例中,您仍然将函数附加到实例:

     

this.methodA = this.methodA.bind(this)

     

所以它们本质上是相同的。

     

在Facebook,我们使用第二种方式(“类属性”),但请注意   这仍然是实验性的,不是ES6的一部分。如果你只想   坚持使用稳定的语法,那么您可以手动绑定它们。

答案 2 :(得分:1)

这将导致在每个render调用上创建一个新的绑定函数:

render() {
    <button onClick={this.myMethod.bind(this)}>Click me</button>
}

请注意,如果在多个位置使用myMethod,则需要多次bind调用,并且如果缺少bind之一,可能会导致未绑定的回调。

这会在组件实例化时创建绑定函数:

  constructor() {
    super();
    this.myMethod = this.myMethod.bind(this);
  }

推荐第二个选项。

autobind这样的装饰器可以用来跳过myMethod在构造器中的显式分配。

this answer中所述,具有bind的原型方法比箭头实例方法具有更少的缺点,并且通常是首选。

答案 3 :(得分:0)

我从eslint-plugin-react文档中获取了此信息:

  

JSX prop中的绑定调用或箭头函数将在每个渲染器上创建一个全新的函数。这对性能不利,因为这将导致以不必要的方式调用垃圾回收器。如果将新功能作为道具传递给组件,而该组件使用该道具上的引用相等性检查来确定是否应更新,则也可能导致不必要的重新渲染。

作为我的补充说明,在JSX中使用this也会引起混淆。我鼓励您阅读以下文档:https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

答案 4 :(得分:0)

  

您应避免使用箭头功能并在渲染中进行绑定。破坏性能   诸如shouldComponentUpdate和PureComponent之类的优化。

有关出色的阅读和演示,您可能希望参考 this.

答案 5 :(得分:0)

第一种方法是正确的性能明智的选择,因为在每个渲染器上,此onClick道具将指向同一对象,而在第二个示例中并非如此。


如果看下面的示例,当我增加计数器时,将看到MyPureCompOne不会渲染,但是MyPureCompTwo会渲染。因为每次<App>组件呈现时,MyPureCompTwo道具handleClick都被分配了一个新的函数对象,这就是为什么作为纯组件的props浅浅比较是错误的,并且会呈现。不需要此渲染。但是MyPureCompOne的情况并非如此,因为每次App渲染时,handleClick道具仍指向相同的函数对象(this.handleClickOne),该对象是在App首次安装。

class MyPureCompOne extends React.PureComponent {
  render() {
    console.log("rendring component one");
    return <button onClick={this.props.handleClick}>First Button</button>
  }
}

class MyPureCompTwo extends React.PureComponent {
  render() {
    console.log("rendring component two");
    return <button onClick={this.props.handleClick}>Second Button</button>;
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
    this.handleCountChange = this.handleCountChange.bind(this);
    this.handleClickOne = this.handleClickOne.bind(this);
  }

  handleCountChange() {
    this.setState(prevState => ({
      count: prevState.count + 1
    }));
  }

  handleClickOne(e) {
    console.log("Clicked..");
  }

  handleClickTwo() {
    console.log("Clicked..");
  }

  render() {
    const { count } = this.state;
    return (
      <div>
        <button onClick={this.handleCountChange}>Change Counter</button>
        <MyPureCompOne handleClick={this.handleClickOne} />;
        <MyPureCompTwo handleClick={this.handleClickTwo.bind(this)} />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>


<div id='root'></div>