15

I can see different style of assigning event handler to the button onClick event. Can anyone suggest when to use inline function on button onClick event handler?

onClick={props.handleDeleteOption(props.optionText)}; // Call the handler directly

onClick={(e) => {
          props.handleDeleteOption(props.optionText);
        }} // Call the handler through inline-function
Prem
  • 5,685
  • 15
  • 52
  • 95
  • 1
    As everyone has mentioned, there is a typo in your top example. Without binding the parameters this function will fire on page load instead of onClick. In order to pass parameters use `props.handleDeleteOption.bind(this, props.optionText)` and you may need to add `this.` to the beginning of this due to scoping issues. – Phillip Thomas May 15 '18 at 13:14

4 Answers4

25

Performance

Whether or not you use inline event handler functions it has an impact on the performance of the app.

Inline event handlers are anonymous functions. They are created every time the component renders. That is, every time you call setState or when the component receives new props.

Whenever a component is about to be rendered (when the state has been updated or receives new props,) react performs a shallow comparison between the previous DOM and the new DOM for that component. If they are found to have different props from the props before the state update, then the component will re-render that particular component and all its child components. If not, it assumes the component is the same as the old DOM and so it doesn't render it.

Now inline functions are objects (functions are objects in javascript.) And when react compares functions, it does a strict comparison. The inline function might not have changed in its value, but it is an entirely different function (different reference in memory) and so React detects that there has been a change. And when there is a change, React re-renders the component and all its children.

Again, let me just state that performance decisions are usually largely tradeoffs. This explanation doesn't mean that you should remove all inline event handlers and define them at the class level. This can slow down the first render for your component because of the binding that has to be done in the constructor. There is also this thing called premature optimization which can lead to poor quality of code or it just might not be worth it.

Awa Melvine
  • 3,797
  • 8
  • 34
  • 47
  • I don't think this accurately explains how React works. React doesn't check props, it rerenders the shadow dom tree at and below where a state change has happened. In the case of a pure component, it does a shallow comparison of the props and doesn't continue. In other cases, it continues checking the shadow dom between the real dom regardless. I would think there is a performance trade-off though since react might be repeatedly readding the handler to the underlying dom element it is ultimately assigned to. – rubixibuc Feb 12 '22 at 16:03
5

According to the ReactJS documentation:

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>

<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>

The above two lines are equivalent, and use arrow functions and Function.prototype.bind respectively.

In both cases, the e argument representing the React event will be passed as a second argument after the ID. With an arrow function, we have to pass it explicitly, but with bind any further arguments are automatically forwarded.

This can be found at the bottom of this link: https://reactjs.org/docs/handling-events.html

Phillip Thomas
  • 1,450
  • 11
  • 21
  • 4
    This is a difference between using arrow functions and `function.prototype.bind`. I feel the OP has not asked for difference between those, since you are using `bind` and the OP's question doesn't contain a reference to `bind` in any sort. – illiteratewriter May 15 '18 at 13:01
4

The main difference is about how you wrote your function. Examples from documentation:

class LoggingButton extends React.Component {
  // This syntax ensures `this` is bound within handleClick.
  // Warning: this is *experimental* syntax.
  handleClick = () => {
    console.log('this is:', this);
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        Click me
      </button>
    );
  }
}

And the second one:

class LoggingButton extends React.Component {
  handleClick() {
    console.log('this is:', this);
  }

  render() {
    // This syntax ensures `this` is bound within handleClick
    return (
      <button onClick={(e) => this.handleClick(e)}>
        Click me
      </button>
    );
  }
}

But as you can read in documentation, second approach is worse from performance perspective.

Leo Odishvili
  • 1,004
  • 1
  • 7
  • 29
1

onClick={props.handleDeleteOption(props.optionText)}; this will cause props.handleDeleteOption(props.optionText)} to be called without clicking the button.

In javascript, let there be a function called foo, foo() will call the function whereas foo itself will be the reference to that function.

So when you do as in the second case, the function is passed to the onClick handler and will be triggered only onClick. The first line of code will not work as expected since it is being called there itself. If you did not have to pass any data to the function, you could also have had written onClick={props.handleDeleteOption}(notice there are no brackets), and that would work as expected.

But since there is data, the only way you can write it is by onClick={(e) => {props.handleDeleteOption(props.optionText)}}

illiteratewriter
  • 4,155
  • 1
  • 23
  • 44