Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.js and ES6: Any reason not to bind a function in the constructor

I'm in the process of updating a React component to ES6 and suffered the problem described in this question - Unable to access React instance (this) inside event handler - namely not binding to the component instance.

That made sense and of course worked, but I'm confused about the other part of the answer:

Be aware that binding a function creates a new function. You can either bind it directly in render, which means a new function will be created every time the component renders, or bind it in your constructor, which will only fire once.

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

vs

render() {
  return <input onChange={this.changeContent.bind(this)} />;
}

I'm assuming that binding in the constructor is the preferred approach for performance etc, but you know what they say about assume!

What are the trade-offs for these two approaches? Is there ever a situation where one is definitely better than the other? Or does it not matter?

like image 953
MattDuFeu Avatar asked Jul 08 '15 13:07

MattDuFeu


People also ask

Why do you need to bind a function in a constructor?

bind(something) returns a new function, in which references to this will refer to something . This is a way of saving the current value of this , which is in scope during the call to the constructor, so that it can be used later when the function is called.

Why binding is necessary in React?

When we bind the this of the event handler to the component instance in the constructor, we can pass it as a callback without worrying about it losing its context. Arrow functions are exempt from this behavior because they use lexical this binding which automatically binds them to the scope they are defined in.

How do you avoid the need for binding in React?

To avoid the need for binding we have something introduced in ES6 as arrow functions. Using the arrow function to call this. setState will lead to avoid the use of bind.

Will ES6 classes bind the instance automatically?

[React Component Class] Methods follow the same semantics as regular ES6 classes, meaning that they don't automatically bind this to the instance.


2 Answers

Downside of binding in the constructor: react hot loader won't work.

Downside of binding in render(): performance.


Recently I've been doing this. It's slightly faster than binding in render, but I'm willing to trade the performance for flexibility and my coveted HMR.

render(){
  return <input onChange={(e) => this.handleChange(e.target.value)}>;
}

It gives a little more flexibility, for example, and easier transition to the canonical Input atom.

render(){
  return <input onChange={(x) => this.handleChange(x)}>;
}

Or adding arguments where you want them:

render(){
  return (
    <ul>
      {this.props.data.map((x, i) => {
        // contrived example
        return (
          <li 
            onMouseMove={(e) => this.handleMove(i, e.pageX, e.pageY)}>
          {x}
          </li>
        );
      }}
    </ul>
  );
}
like image 75
Brigand Avatar answered Oct 14 '22 18:10

Brigand


I think you've addresses the main problems to do with recreating functions. I'd like to highlight another option using arrow functions and property initializers. The arrow functions in this case will automatically adopt the local this.

e.g.

class MyClass extends React.Component {
  changeComponent = (e) => {
    // this will refer to the component
  }

  render = () => {
    return <input onChange={this.changeContent} />;
  }
}

You can read more about it here: http://babeljs.io/blog/2015/06/07/react-on-es6-plus/

When you have many functions you'd want to bind, this may be a better solution. You do lose the cleanness of just using a standard function declaration, though.

like image 45
rbhalla Avatar answered Oct 14 '22 17:10

rbhalla