Difference in handling onClicks with functions REACT - javascript

What is the difference between these two lines:
<button onClick={() => this.updateTodoToShow("all")}>all</button>
and
<button onClick = {this.deleteCompleted}>delete completed</button>
Why is one called with an arrow function and not the other? When is it appropriate to do each of these? Here is the full code for those two functions:
deleteCompleted = () => {
this.setState({
todos: this.state.todos.filter(todo => !todo.complete)
});
};
updateTodoToShow = s => {
this.setState({
todoToShow: s
});
};

The first uses an anonymous arrow function in order to pass a value other than the event to the function updateTodoToShow.
The second apparently does not need to pass anything besides the click event which is the default argument (in fact, it doesn't appear to use the event either), so it only passes the function reference to this.deleteCompleted.
If no extra parameter is needed for the event handler, passing only the function reference is better. Creating an unnecessary inline function is pointless, like in the following:
onClick={(e) => this.handler(e)}
Is functionally equivalent to below, there is just no unnecessary in-between function:
onClick={this.handler}
The main thing to understand here is that both methods are passing onClick a function reference. The first is passing a reference to the inline function, the second is passing a reference to the deleteCompleted function.
It is appropriate to use the inline function only when you need to add extra arguments to the handler. Another common usecase would be passing an id or other identifier when creating buttons in a loop.

Related

What's the difference between onClick ={ () => function()} and onClick = {function()}?

What's the difference between this code:
<button onClick={()=>props.submitHandler(searchInputValue)}>Submit</button>
and
<button onClick={props.submitHandler(searchInputValue)}>Submit</button>
The difference is the first one has the parentheses and the second one doesn't. Without the parentheses, my app seems to be re-render indefinitely. Can someone kindly explain it to me?
In first one:
<button onClick={()=>props.submitHandler(searchInputValue)}>Submit</button>
This is arrow function and it will trigger only onClick of the button.
In second one:
<button onClick={props.submitHandler(searchInputValue)}>Submit</button>
This is a normal function call , which calls the method as soon the rendering of the component happens.
The first creates a function that calls submitHandler with an argument and assigns that function to onClick.
The second immediately (i.e. during the render step) calls submitHandler with an argument and assigns the return value to onClick.
Remember the fact that a function is assigned to onClick via {} doesn't mean that it will be triggered on html user request. The {} is a compile time action.
Another words:
onClick=> {execute what is here at compile time and assign the result into onClick action}
If you have a props.submitHandler() function call inside {} it will be executed and return value assigned to onClick.
If you have a ()=>props.submitHandler it is an arrow function and its execution will be "binded" to onClick user action. Traditional method of doin' it (without using fancy arrow functions) would be
<button onClick={function(){props.submitHandler(searchInputValue)}}>Submit</button>
In first one arrow function returns back a function which is assigned to the onClick
In the second one we call the function when the component renders hence it's not assigned to the onClick handler of the button as function pointer is not returned in the second case.

React - Arrow function vs bind() and event with argument

I'm a newbie in react (even in JS). I'm made the following code in my App class:
nameChangeHandler = (event, personId) => {
//method code
};
render()
{
<div>
{this.state.persons.map((person, index) => {
return <Person
// nameChangeHandler={(event) => this.nameChangeHandler(event, person.id)}
nameChangeHandler={this.nameChangeHandler.bind(this, person.id)}
/>
})}
</div>
}
I'm passing nameChangeHandler to Person component where I call it in onChange event in input tag (<input type="text" onChange={props.nameChangeHandler}/>)
Application works fine when I pass it in this way:
nameChangeHandler={(event) => this.nameChangeHandler(event, person.id)}
but it doesn't when I do it like this:
nameChangeHandler={this.nameChangeHandler.bind(this, person.id)}
It fails with an exception when I'm trying to acces event.target.value in nameChangeHandler method.
How can I pass event and argument to this method using bind() method instead of arrow function?
I've heard we should always use bind() approach over the arrow function because an arrow function approach could render component many times.
Is there any special use cases and differences between bind() and arrows functions?
It's a matter of timing.
When you use bind, the arguments map on to the function you are binding in the order you bind them followed by any that are passed to the new function.
When you use an arrow function, you are explicitly passing them in the order you determine.
Your function expects event to be the first argument, so when you use an arrow you function you pass event, person.id. However, when you bind you pass person.id (the first argument) and when the function is called with event you pass that (as the second argument).
This means you arguments end up the wrong way around.
Since you only have person.id when you call bind and you don't get event until later, the only way you can use bind for this is to change the original function so it accepts the arguments in a different order.
nameChangeHandler = (personId, event) => {

when to use function() , function or () => function(callback)

I have been searching for a while for a good explanation so its all clear to me.
Example:
<Char click={()=>this.onDeleteHandler(index)}/>
vs
<Char click={this.onDeleteHandler()}/>
vs
<Person changed={(event) => this.nameChangedhandler(event, person.id)} />
and
<Char click={this.onDeleteHandler}/>
regarding the third code , here is the property called:
nameChangedhandler = (event, id) => {
const personIndex = this.state.persons.findIndex(p => {
return p.id === id;
});
// copying the person with the right index
const person = {
...this.state.persons[personIndex]
};
// Assigning new name to this person
person.name = event.target.value;
// copying array of persons, then manipulating the correct object of person by using the index
const persons = [...this.state.persons];
persons[personIndex]= person;
this.setState({
persons: persons
});
}
some aspects are clear to me, but definitely not 100%!
So if you can provide me with an explanation, link or similar that would be great!
thanks!
<Char click={()=>this.onDeleteHandler(index)}/>
It passes anonymous function as a callback which - when clicked - triggers onDeleteHandler with extra index parameter (which has to be defined in the scope before).
<Char click={this.onDeleteHandler()}/>
It passes result of onDeleteHandler() as a callback - probably a bad idea - onDeleteHandler function has to return another function that will be invoked on click.
<Person click={changed={(event) => this.nameChangedhandler(event, person.id)} />
Looks invalid - will result with syntax error.
<Char click={this.onDeleteHandler}/>
Similar to the first example but doesn't take custom parameters. Default click event will be passed as a first argument for onDeleteHandler
The whole question seems to boil down to what the difference between func and func() and () => func() is. It has nothing to do specifically with React.
If I have a function
function func() {
console.log(42);
}
Then I can reference the function object itself via func. This is useful if I need to pass the function to another function, e.g. setTimeout:
setTimeout(func, 1000); // calls func after 1000ms
setTimeout expects a function that it can call after the provided timeout.
Similarly in React, click, change etc are all props that expect to be passed a function that is called when the event happens.
func() on the other hand calls the function. This needs to be done if you actually need to call function right then and there.
This implies that if I do
setTimeout(func(), 1000);
then I would call func first and pass its return value to setTimeout (i.e. I call func now, setTimeout doesn't call it later). So this is usually incorrect unless func returns a function itself and its really the return value I want to pass to the other function.
() => func() is just a new function that only calls func. For all intends and purposes it is equivalent to func:
function func() {
console.log(42);
}
const anotherFunc = () => func();
func();
anotherFunc();
And of course if func expects an argument then I have to pass it along when wrapping it in another function, which is what x => func(x) does.
The other part is how functions assigned to object properties and this work. In short, what this refers to inside a (non-arrow) function depends on how the function is called. Doing
this.foo();
// or
var bar = this.foo;
bar();
produces two different results because this.foo() and bar() are two different ways to call the function. For more info see How to access the correct `this` inside a callback?
Generally you would make use of inline arrow functions when you need to bind he handler to the context or to provide custom parameters
In
<Char click={()=>this.onDeleteHandler(index)}/>
onDeleteHandler is bound to the context where Char is rendered and is passed a custom parameter index. Since a new function is returned to click , it can be executed from within Char like this.props.click()
<Char click={this.onDeleteHandler()}/>
Here the onDeleteHandler is evaluated and the value is returned to the click prop
<Person click={changed={(event) => this.nameChangedhandler(event, person.id)} />
Here the syntax is invalid, it should probably be
<Person changed={(event) => this.nameChangedhandler(event, person.id)} />
In which case, it takes the default parameter and pass it along with the custom parameter to nameChangedHandler and it also performs binding
<Char click={this.onDeleteHandler}/>
just assigns the reference of onDeleteHandler to click and whenever you invoke click, onDeleteHandler will be called with the parameters that you pass while invoking click and the context within onDeleteHandler will refer to the context from where it is invoked unless you bind onDeleteHandler using arrow function or in constructor

How to use bind in React?

I'm using React, and I saw that one common practice is to bind the functions in the constructor, which I also want to use. Though, I don't exactly get how bind works for functions that take parameters. For example, I have something like this:
class MyClass extends Component {
constructor(props) {
super(props);
this.onListClicked = this.onListClicked.bind(this);
}
onListClicked(id) {
// performs some action
}
render() {
return (
// partially removed for brevity, value of myId comes from a loop
<ListItem onClick={ () => this.onListClicked(myId) } />
);
}
}
Now this works in my case, but I'm not taking advantage of bind fully. If I change the ListItem to <ListItem onClick={this.onListClicked} /> it doesn't work as expected. This would have worked if onListClicked didn't accept any parameters. But, in this case I don't know how to take advantage of bind. Any ideas?
your question has little to do with binding, and is really about how React handles callback props.
Every React event-listener function is passed an instance of React's SyntheticEvent object as its first parameter.
onClick={this.onListClicked} will call the onListClicked function and pass it one parameter: the SyntheticEvent object provided by React.
onClick={this.onListClicked.bind(this)} is the same as the last example. onListClicked.bind() returns a wrapped version of onListClicked with its context object set to this (which in your case is your React component because that's what this is set to when you do the binding). This wrapped version of your function still only receives one parameter: a SyntheticEvent object.
onClick={(e) => this.onListClicked(myId)} will call the anonymous fat-arrow function and pass it one parameter: a SyntheticEvent object, because the anonymous fat-arrow function is the callback and all callbacks get that parameter. This anonymous fat-arrow function ignores its own parameters, and calls this.onListClicked with the value of myId.
onClick={() => this.onListClicked(myId)} is the same as the last example, except we are ignoring the SyntheticEvent because we don't care about it.
onClick={this.onListClicked.bind(this, myId)}, as suggested in another answer, will wrap and call the onListClicked function and pass it TWO parameters: the first is myId (since bind is injecting myId as a parameter as well as setting the context to this) and the second is a SyntheticEvent object.
So: depending on what exactly you are doing inside of onListClicked, you may or may not need to bind it to your React component (or to some other context). Do you actually need variables and functions defined inside a particular object? Then bind your callback context to that object, and call this.foo or this.bar all you need. But if you don't need access to those sorts of things, there's no need to use bind just because it's there.
bind function takes a context as its first argument and takes your original function arguments as the next set of arguments after this. The "binded" (excuse me for the horrendous grammar!) function that is returned has the same arguments "binded" to it so when you call it, it will be called with the same set of arguments that it was bound with.
So essentially a <ListItem onClick={ () => this.onListClicked(myId) } /> should be replaced by a <ListItem onClick={this.onListClicked.bind(this, myId)} />
I, however, don't see a way for you to generate the function you need in the constructor itself since you won't have those arguments there to start with. You could loop over the array in the constructor itself and create those "binded" functions there only but that would be just a waste and a much elegant solution would be to use the above said method.
Read more about bind from MDN.

What is the meaning of 'function(event)' in js

I don't know the meaning of the sentence 'function(event)'
Event.add(apple,'click',function(event) {
Event.stopPropagation(event);
});
Isn't the argument 'event' is the unique keyword of javascript?
Is keyword can be an argument of some function?
I understand the meaning of below code :
function(test) {
alert(test);
}
But I don't understand this one :
function(event)...
Can any one give an explanation about that to me?
The event object is always passed to the handler and contains a lot of useful information what has happened.
Different types of events provide different properties. For example, the onclick event object contains:
event.target - the reference to clicked element. IE uses event.srcElement instead.
event.clientX / event.clientY - coordinates of the pointer at the moment of click.
Information about which button was clicked and other properties.
Please visit this link.
It answers all your questions very simply
Source http://javascript.info/tutorial/obtaining-event-object
Example:
Like if in HTML you have assigned an event like this
<button onclick="alert(event)">See the event</button>
then
function alert(event) {
// event.type contains whether this event was invoked in the result of a click etc
// event.target would contain the reference to the element which invoked this method/event
}
It is an anonymous function, that is a function without name, that sends the event object. That object contains information about the event itself. It is always passed as first object/variable.
It is defining an anonymous function object. This code:
function foo(bar) { ... }
Is functionally similar to:
var foo = function (bar) { ... };
(Except that in the first case the name foo and the creation and assignment of the function object are hoisted to the top of the scope, while in the second case only the name foo is hoisted; foo won't hold the function until the assignment executes.)
Effectively, the code you posted is calling Event.add() and passing a function to it as the third argument, but rather than declaring the function ahead of time it is creating the function object inline.
Another way to write the code block in your question is:
function handler(event) {
Event.stopPropagation(event);
}
Event.add(apple, 'click', handler);
Except that the code in your question does not introduce the handler name.
Note that there is no such method Event.stopPropagation(). However, the event object will have a stopPropagation(), so the capital E was probably a typo. It's likely that the intent was to use function (event) { event.stopPropagation(); }.
event is just a variable that's passed to event listener functions such as Event.add, element.on. It's not reserved (although Event is, which is why you can use Event.add), and you can name it whatever you like.
The event argument is used to pass information about the event that has happened (the click on apple in this case), which can be used to retrieve data about the event or manipulate it.
function(){...} is an anonymous function, which means that you don't need to name it, you can just declare it inline, and the function will be passed as an argument, as if you said
function foo (event) {
...
}
Event.add(apple, "click", foo);
but you don't need to declare it before hand. It does come at the disadvantage of not being duplicable, for instance when clearing an event handler.
Look at the event variable and you will all understand :)
function (event) {
console.log({ event });
}

Categories