JavaScript - Arrow Functions This in Event Handler

Why do I have to use arrow function in event handler of react?

without the arrow function, every button click renders the page again, which sets the state, then it renders again, and sets the state, then it renders again. infinite loop
the arrow function recreates that function once when it mounts/updates.

read more here https://reactjs.org/docs/faq-functions.html

Using arrow functions and event.target with event handlers to get scope instead of normal functions and the this keyword?

However, with so many articles recommending against using arrow functions in event handlers, I am wondering if there are any disadvantages to my approach that I may have missed?

It doesn't look like you have missed anything. You are not using any of the "features" that make arrow functions different from "normal" functions.

You are

  • not using this
  • not using arguments
  • not calling the function with new (and the browser doesn't either)

so you can choose either form.


If I remember correctly event.target didn't exist in older versions of Internet Explorer (< 9) (instead it was event.srcElement), but if you are using an arrow function you probably don't care about deprecated browsers ;)

Bind vs Arrow Function when passing onChange props (React)

Since it is only using a reference to the function, we are not causing a re-render each time

You're wrong.

The bind method returns a new function (so will trigger a re-render).


To avoid re-renders, make use of the useCallback hook.

Or, since you don't appear to be making use of this inside myFunction (otherwise () => myFunction() would break it), just pass myFunction itself without creating a new function.

onClick={myFunction}

Arrow function in AddEventListener not working

Because this in your arrow function doesn't point to the <input> element. It points to the scope wherein the arrow function was created. Read about it on MDN.

EDIT: Answer to question in comments

In your case, if you want to use an arrow function in your event listener, just re-use the hider variable instead of this:

hider.addEventListener('click', () => {
// use "hider" instead of "this"
hider.hidden = true;
});

Taking it further

If you'd want to create an "element-agnostic" event handler, make it a higher order function that takes in the element to hide as a parameter and that returns an (here: anonymous) handler function. If this sounds cryptic to you, here's some example code:

const makeHideHandler = (element) => { // higher order function
return () => { // event handler function
element.hidden = true; // action to perform
};
};

With this, you can write a one liner to add the listener:

hider.addEventListener('click', makeHideHandler(hider));

If you want to know why it works, google for "closures".

However, the real strength of the higher order function approach becomes visible if you have more than one element that should hide the same (or other!) element(s). Consider the following:

Let's say, you have multiple buttons that, when pressed, should hide the same element. It's easy peas with makeHideHandler:

// grab all "button" elements
const hideButtons = document.querySelectorAll('.hide-button');
// grab the element to hide
const elemToHide = document.querySelector('.hide-me');

// make the handler, pass in the element that should be hidden
const hideHandler = makeHideHandler(elemToHide);

// add listeners to the buttons
hideButtons.forEach((button) => {
button.addEventListener('click', hideHandler);
});

Or to create buttons that hide themself after pressing:

const hideButtons = document.querySelectorAll('.hide-button');
hideButtons.forEach((button) => {
button.addEventListener('click', makeHideHandler(button)); // <-- pass in the button element
});

How does event handlers with arrow functions achieve context binding

As the MDN docs states

An arrow function does not have its own this; the this value of the
enclosing execution context is used

So you would think of

onClick={(e) => this.goToStore(e)}

as being an anonymous function which can be written as

    (e) => { 
return this.goToStore(e)
}

Now here in this anonymous function this refers to the lexical context of the render function which in turn refers to the React Class instance.

Now

Context is most often determined by how a function is invoked. When a function is called as a method of an object, this is set to the object the method is called on:

var obj = {
foo: function() {
return this;
}
};

obj.foo() === obj; // true

The same principle applies when invoking a function with the new operator to create an instance of an object. When invoked in this manner, the value of this within the scope of the function will be set to the newly created instance:

function foo() {
alert(this);
}

foo() // window
new foo() // foo

When called as an unbound function, this will default to the global context or window object in the browser.

So here since the function is called like this.goToStore() this inside it will refer to the context of React component.

However when you write onClick={this.goToStore}, the function is not executed but a reference of it is assigned to the onClick function, which then later invokes it, causing this to be undefined inside the function as the function runs on the context of the window object.

Now even though onClick={(e) => this.goToStore(e)} works, whenever render is called a new function instance is created. In your case its easy to avoid, just by created the function goToStore using arrow function syntax.

goToStore = (e) => {

}

Check the docs for more details on this



Related Topics



Leave a reply



Submit