4

I learn React now and noticed that a lot of people bind their methods in constructor.

Like this:

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

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

  myMethod() {
    // do something
  }
}

But I got used to writing something like this:

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

And I was told by a couple of people that using the second method is a bad experience.

So could you tell me the differences between first and second methods? Any pros and cons? or performance issues?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Dils Matchanov
  • 507
  • 1
  • 5
  • 19
  • 3
    Any impact in performance caused by this would be minimum. It's more about having less javascript code in your JSX, making it more readable. – Phiter Sep 05 '18 at 18:17
  • 1
    From what I understood in the second example you are binding and creating a new function every time render is called, but as I am not sure about this, if anyone knows if its right or not, feel free to correct me. – Bruno Mazzardo Sep 05 '18 at 18:19
  • 1
    @BrunoMazzardo you are correct. a new function is created every time render is called. This will cause children that rely on the prop to re-render because of the new object being a change. – emran Sep 05 '18 at 18:23
  • Nice, I recommend this link to see others approach this problem https://medium.freecodecamp.org/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56 – Bruno Mazzardo Sep 05 '18 at 18:25
  • This topic is discussed ad infinitum in so many other resources about React that you can find on the web that it's really unnecessary here – Dexygen Sep 05 '18 at 18:25

6 Answers6

4

You are right and what others told you is also right.

You are encouraged to do binding in constructor because constructor gets called only once per component so if you do binding in constructor it creates a new object/function only once in Webpack bundle.js file hence not much impact

You are not encouraged to do binding directly in render because a component renders for several reasons like when you do setState, when your component receives new props so your component will render so many times. So since you are binding directly in render whenever your component renders it will create a new function every time in Webpack bundle.js and your bundle file size will increase and that affects performance when your app contains thousands of components and if you do binding directly in render in every component.

So you are recommended to do binding only in constructor. Hope that clarifies

Hemadri Dasari
  • 32,666
  • 37
  • 119
  • 162
2

This results in creating a new bound function on every render call:

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

Notice that if myMethod is used in multiple places, this requires multiple bind calls and may result in unbound callback if one of bind is missing.

While this creates bound function on component instantiation:

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

The second option is recommended.

A decorator like autobind can be used to skip myMethod explicit assignment in constructor.

As explained in this answer, prototype methods with bind have less shortcomings than arrow instance methods and can be generally preferred.

Estus Flask
  • 206,104
  • 70
  • 425
  • 565
1

First approach is correct performance wise, because on every render this onClick prop will be pointing to the same object, which is not the case in the second example.


If you look at the below example, you will see when I increment the counter, the MyPureCompOne doesn't render, but MyPureCompTwo does. Because each time time the <App> component renders, MyPureCompTwo props handleClick being assigned with a new function object, and that is why being a pure component shallow comparisons of props are false and it renders. This rendering was not needed. But that is not the case with MyPureCompOne, as each time time App renders, the handleClick props still pointing to the same function object (this.handleClickOne) which was created when the App first time mounted.

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>
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
1

You should bind in the constructor simply because the second way will create a new function every render.

But there's a better way to simply avoid binding. Use arrow function.

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

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

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

Let's see how the creator of Redux Dan Abramov thinks about bind vs arrow functions -

Question:

In terms of performance, is there any difference between using arrow functions and bind manually when using es6 classes? Using arrow functions the methods are not on the class prototype, it will be on the class instance only. Using bind will attach the methods to class prototype. It sounds like bind manually will have better performance, does that mean we should consider using bind instead of arrow functions for class methods?

Any suggestions or comments are really appreciated!

So in terms of performance, would you recommend using

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

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

or

class MyComponent extends React.Component { constructor(props) { super(props) this.methodA = this.methodA.bind(this) }

methodA() { ... } }

Answer:

These two ways of writing it are equivalent. (The second one is compiled to the first one.)

Using bind will attach the methods to class prototype.

In your example, you still attach the function to the instance:

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

So they’re essentially the same.

At Facebook, we use the second way (“class properties”) but be aware this is still experimental, and not part of ES6. If you only want to stick with stable syntax, then you could bind them manually.

0xC0DED00D
  • 19,522
  • 20
  • 117
  • 184
  • Arrow function also creates a new function if it’s not on outside class every time the component renders. Please take a look at this thread https://stackoverflow.com/questions/52031147/react-which-is-recommended-arrow-or-normal-function – Hemadri Dasari Sep 05 '18 at 18:42
  • @Think-Twice I am referring to class level arrow functions here. – 0xC0DED00D Sep 05 '18 at 18:45
0

I took this from the eslint-plugin-react documentation:

A bind call or arrow function in a JSX prop will create a brand new function on every single render. This is bad for performance, as it will result in the garbage collector being invoked way more than is necessary. It may also cause unnecessary re-renders if a brand new function is passed as a prop to a component that uses reference equality check on the prop to determine if it should update.

As a side note from me, using this in your JSX can be confusing as well. I encourage you to take a look at this doc: https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md

emran
  • 902
  • 6
  • 12
0

You should avoid arrow functions and binds in render. It breaks performance optimizations like shouldComponentUpdate and PureComponent.

For an excellent read and demo you might want to refer this.

Anshul Bansal
  • 1,833
  • 1
  • 13
  • 12
  • 1
    Binding using Function.prototype.bind in render creates a new function each time the component renders, which may have performance implications Also Binding using an arrow function in render creates a new function each time the component renders, which may break optimizations based on strict identity comparison. – Anupama Karunarathna Jul 08 '20 at 15:01