Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'React - ES6 way' of binding click handlers with parameters

I've read a bunch of articles about the use of () => {} syntax, binding in the constructor, binding in the props etc.. but from what I understand, binding this is costly performance-wise, and doing automatic binding with arrow functions is costly because it creates a new anonymous function every time.

So what is the most performant, 'React way' of handling this issue?

Binding in the constructor seems to work well for functions that don't need to pass parameters, like this:

constructor(props) {
    super(props)
    this.handleClick = this.handleClick.bind(this)
}

but how do we handle binding functions that pass params, without binding it in the prop, like this:

<li onClick={this.handleClick.bind(this, item.id)} />{item.name}</li>

Does binding this in the constructor and then binding null or undefined in the prop result in a bound function that only binds once?

Feel free to correct me in any misconceptions I have. It seems like the solution to this problem should be more well-known and universal... that is if I haven't just been living under a rock!

EDIT:

Even with abstraction, doesn't the click handler get bound with every single item render?

in the article here, they give this example to avoid binding the click handler, but because React.createClass does autobinding of methods, I don't see how this is not actually binding on every item render?

var List = React.createClass({
  render() {
    let { handleClick } = this.props;
    // handleClick still expects an id, but we don't need to worry
    // about that here. Just pass the function itself and ListItem
    // will call it with the id.
    return (
      <ul>
        {this.props.items.map(item =>
          <ListItem key={item.id} item={item} onItemClick={handleClick} />
        )}
      </ul>
    );
  }
});

var ListItem = React.createClass({
  render() {
    // Don't need a bind here, since it's just calling
    // our own click handler
    return (
      <li onClick={this.handleClick}>
        {this.props.item.name}
      </li>
    );
  },

  handleClick() {
    // Our click handler knows the item's id, so it
    // can just pass it along.
    this.props.onItemClick(this.props.item.id);
  }
});

Can someone explain this? Doesn't this just look like it avoids binding every ListItem render, but because of autobinding in React.createClass, it still does?

I tried this example with class List extends Component syntax instead of createClass, and this.handleClick was undefined, because the handleClick method wasn't bound to the class.

At the end of the day, it appears that this just cleans up verbosity, and doesn't actually improve performance by reducing method binding...

like image 273
jacoballenwood Avatar asked Dec 09 '16 00:12

jacoballenwood


2 Answers

For your <li onClick={this.handleClick.bind(this, item.id)} />{item.name}</li>

this typically means you need another layer of abstraction IE a new react component that returns the same element but you can pass in the onClick as a prop as well as item id as a prop. Then in that component you would call this.props.onClick(this.props.id) or however you format the data.

this article draws out all the differences between each way of binding instance methods as well as how each impacts performance https://medium.com/@housecor/react-binding-patterns-5-approaches-for-handling-this-92c651b5af56#.

like image 196
finalfreq Avatar answered Sep 22 '22 08:09

finalfreq


If passing a parameter then you must bind in the render function and not in the constructor. This can be done using the bind or an arrow function.

<li onClick={this.handleClick.bind(this, item.id)} />{item.name}</li>

or

<li onClick={() => this.handleClick(item.id)} />{item.name}</li>
like image 44
Wayne Ellery Avatar answered Sep 22 '22 08:09

Wayne Ellery