0

When a click event occurs the event information is available within e, right? I just wanted to try and understand two things, sorry for my ignorance.

The first is: what is 'id' actually held in? Is it a special variable that React gets with onClick. And if so, why is it not this.id?

And also, why is this.deleteRow.bind(this, id) required to bind 'this' again? I wasn't expecting a second 'this' if this.deleteRow is valid. So why does it need to bind 'this' again?

<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
chazsolo
  • 7,873
  • 1
  • 20
  • 44
user1088793
  • 623
  • 2
  • 9
  • 19
  • 1
    Maybe not duplicate but [related](https://stackoverflow.com/questions/52031147/react-which-is-recommended-arrow-or-normal-function/52031676#52031676): – devserkan Mar 27 '19 at 15:19
  • Hi devserkan, I am having a read now thanks. – user1088793 Mar 27 '19 at 15:23
  • I'm not sure that link is that closely related (unless I missed something). The most relevant factor here is the fact that `bind` can be used to "partially apply" a function. – Robin Zigmond Mar 27 '19 at 15:24
  • Yeah, not closely related. Maybe just the `bind` issue and passing the parameters part. – devserkan Mar 27 '19 at 15:25

2 Answers2

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

This version of the event listener makes it clear that the deleteRow method - whose implementation we are not shown - takes two parameters. id is presumably some identifier for the row that should be deleted, whereas e must be the actual event object (because this is always the argument provided by the browser to an event callback).

So this is the most explicit form. But note that if for some reason your code is running in an environment which doesn't support arrow functions (and you're not transpiling it first), this obviously won't work. And the arrow function may be needed because, without it, the this inside the deleteRow method won't be what you expect it to be, in particular things like this.setState won't work.

Unless, that is, you've taken other steps to ensure that the this inside deleteRow will be correct, such as in your second example:

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

The bind method of a function object returns another, related, function, and has 2 handy properties. The first, and most relevant in the context of the above discussion, is the object to which the this reference inside the function will then always refer to. You are "binding" the this reference to always be what you say it is, under all circumstances. (Well unless you try to call the bound function as a constructor with new, which I would argue is not something that you really would ever want to do.) So this avoids the "this problem" you might otherwise have, without the need of any ES6-specific features (.bind has been around since ES5).

The other useful feature of bind, which is completely unrelated to how it binds this, is that all the other parameters to .bind are passed as parameters to the function, and if any are left over, they are taken as parameters to the newly-created "bound function". This is called "partial application" - you "partially apply" the function by passing it some of the arguments it wants, and then pass the others later when you call the newly-created function.

So in this case where deleteRow will have a signature like this:

deleteRow(id, event) {...}

the function myThis.deleteRow.bind(myThis, myId) will, as well as binding all occurences of this inside deleteRow to myThis, creates a new function which takes a single argument, event, and supply that as the second parameter to deleteRow, with the first fixed as myId. So when it's called as an event handler, and passed the event object, it behaves in exactly the same way as the arrow function version above - with the correct this, the particular id desired as the first argument, and the event as the second.

I think there's little doubt that the arrow function version should be the preferred option, being more explicit. And even if you can't do this, you can still avoid the partial application by:

  • binding the function in the constructor: this.deleteRow = this.deleteRow.bind.this, and
  • then using a "normal" anonymous function instead of the arrow function: `onClick={function(e) {this.deleteRow(id, e);}}
Robin Zigmond
  • 17,805
  • 2
  • 23
  • 34
  • Your knowledge is amazing, will have to go through your reply in greater depth to fully appreciate it, thank you. as a second note, is 'id' actually referring to – user1088793 Mar 27 '19 at 15:55
  • 1
    It's not explicitly defined in the original source (see the link in @CharlieK's answer - but from context, as I said, it's presumably a number which identifies the row that would be deleted. I would guess the above ` – Robin Zigmond Mar 27 '19 at 16:00
0

That code block appears to come from Handling Events in the React docs. Your first question is addressed in the description there. ID is specific to the example provided.

id is the row ID

As for your second question, the two lines of code represent two syntactical options.

if id is the row ID, either of the following would work:

You can choose which version to use in your implementation.

It'sNotMe
  • 1,184
  • 1
  • 9
  • 29
  • Hi, my first question is where is id held in, if it is in the row id, why isnt it this.id? Thats what I don't get. – user1088793 Mar 27 '19 at 15:42
  • And for the second question, either should work, but doesn't explain why this is bound to a function which is referenced within this, if you know what i mean – user1088793 Mar 27 '19 at 15:42