React.js and ES6: Any reason not to bind a functio

2020-02-10 20:09发布

问题:

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?

回答1:

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>
  );
}


回答2:

I think all you've to understand is Function.prototype.bind() will return a new function. So you'll basically be doing a creation every time by performing the binding action in the render() method. Chances of the render() method being called multiple times is really high.

So doing that in the constructor means you end up binding only once and you can re-use it as many times as you want. Even if the render() method is called multiple times the same function created with a different bound context will be used.

Yes, ideally you should bind in the constructor. Reminds me of a piece of code (check the constructor) I was going through a couple of weeks back.



回答3:

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.