2

Is there any difference between both the button click event in the given component? Which is the preferred way to write?

export default class App extends Component {
  doSomething = () => {
    console.log('Hi');
  }
  render() {
    return (
      <Container>
        <Button onClick={this.doSomething} title="Test" /> 
        <Button onClick={() => this.doSomething()} title="Test" />
      </Container>
    );
  }
}
chunkydonuts21
  • 79
  • 1
  • 10

3 Answers3

4

When you don't need to pass the parameter, you can just use

{this.doSomething}

But if you need to pass the parameter to the function, then this will cause your method to execute immediately:

{this.doSomething(param)}

Thus, not to execute the function immediately, we need to use arrow method like you used:

{() => this.doSomething(param)}

Thus, in your case both are same. Because they are only executed when onClick is called ie. you click on the element.


Bonus:

You can still use the first way even you want to pass the parameter:

{this.doSomething(param)}

But for this, you need to define your method like this:

doSomething = (param) => () => {
  console.log('Hi');
}

Furthermore, if you wish to use event object, then you may use like below:

doSomething = (param) => (event) => {
  console.log('Hi');
}

Or, with the second approach ie. with arrow function:

{(event)=>this.doSomething(event,param)}

And obviously, if you are worried about performance, I would suggest not to use inline arrow function. The preferred way to use:

doSomething = (param1, param2,) => (event) => {

Misunderstanding:

Some people might find the method that pass the parameter without using inline arrow function will also work. But this is incorrect. Let me clarify on this.

When you use {this.doSomething(param)}, this function seems to work fine with its parameter. But if you change the state inside the handler, then you'll know the big difference. You'll get error maximum update depth exceeded react.

But with the same, you can avoid that error and also avoid the performance issue, you'll need to define the method like I stated before with arrow function:

doSomething = (param) => () => {
Bhojendra Rauniyar
  • 83,432
  • 35
  • 168
  • 231
  • 1
    There is a _performance_ problem with the 2 approaches. When you want to pass the arguments, you can do `this.doSomething.bind(param, this)` instead of `{() => this.doSomething(param)}` or use _partial function_ with class property syntax.. Arrow syntax is not good way for this. Check [this](https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers) – Arup Rakshit Aug 15 '18 at 17:03
  • I don't think OP is asking for differences between them regarding the performance. But how they work. – Bhojendra Rauniyar Aug 15 '18 at 17:09
  • 1
    The subject says *What is the difference between both button click..*. Sorry to say your answer is not on track. The actual difference is the *performance* issue. Passing arguments is not the problem here. Arguments can be passed without using *arrow function*. – Arup Rakshit Aug 15 '18 at 17:10
  • Why? Did you check the link https://reactjs.org/docs/handling-events.html#passing-arguments-to-event-handlers ? The OP here not passing any arguments except the default `event` which React will take care of. For own params passing, the method definition can be changed, and can be called without Arrow function. Check the official doc, it has all the examples. – Arup Rakshit Aug 15 '18 at 17:12
  • @ArupRakshit I'm not sure I understand your first comment; the difference between an arrow function and a `bind` is event parameter passing--if you don't need it, or just want to pass it manually, why would it matter? – Dave Newton Aug 15 '18 at 17:17
  • I'm not saying OP code won't work. I am just clarifying your comment. Read my answer carefully. – Bhojendra Rauniyar Aug 15 '18 at 17:18
  • 1
    I know OP's code work. OP defined the method, with class property syntax. So it is a bound function already. So first thing, arrow function is pointless. And even if it was not binded like it is not, the OP could .bind() for the same. In either way it is fine, no need to pass arrow function. That said, I'll not comment any more, as it seems you are not getting my point. But i'll keep these comments for future readers. – Arup Rakshit Aug 15 '18 at 17:51
  • @BhojendraRauniyar Do you have a codepen that show that the function is not recreated ? I tried your approach with no luck : https://react-ec17us.stackblitz.io – Ant1 Jan 11 '22 at 22:22
2

From doc

<Button onClick={() => this.doSomething()} title="Test" />

The problem with this syntax is that a different callback is created each time the Button renders. In most cases, this is fine. However, if this callback is passed as a prop to lower components, those components might do an extra re-rendering.

<Button onClick={this.doSomething} title="Test" /> 

We generally recommend binding in the constructor or using the class fields syntax, to avoid this sort of performance problem.

Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
0

First we will look when to use both:

  1. onClick={this.doSomething} : This is using class variable directly, but it cannot be used when we are required to pass parameters to the function. For that, the second way comes to rescue. A way to pass parameters to this is :

    onClick={this.doSomething.bind(params, this)}

  2. onClick={() => this.doSomething()}: you can pass parameters to the function as

    onClick={() => this.doSomething(param1, param2)}.

Also, an important point to note, when the component re-renders, memory is allocated for the second one every time, while the first one just uses memory reference. So, first one is better if you don't have to pass parameters in the function.

McRist
  • 1,708
  • 11
  • 16