I was creating a form using ReactJS and displaying an array of user names and identifiers; while adding a delete button to allow deleting a user from the list.
I have the following handleDelete function:
const handleDelete = (id) => {
const newUsers = users.filter((person) => person.id !== id);
setUsers(newUsers);
};
When I call this function via a button on onClick={handleDelete(user.id)}
it doesn't work but when I call it as onClick={() => handleDelete(user.id)}
it works, can anyone explain the difference between these two approaches?
If we have been asked the question : What is the difference between a function invocation expression and a function definition, then the two cases highlighted in this question may be the respective answers by example.
The sample codes below reiterate the same point.
const fn = ()=>1; //this is a function definition statement.
fn(); // this is a function invocation statement.
Now coming to this question
The intent of the code below is to assign an handler for click event of a button element.
onClick={handleDelete(user.id)} // code 1
onClick={() => handleDelete(user.id)} // code 2
And it is intended to work as below.
// 1. Once the App has been loaded,
// 2. The button will come into display.
// 3. Then the user may click on it.
// 4. In response the handler should be called by React.
// 5. And the logic in the handler must be carried out, which is essentially
// a state setter in this case.
The intention will be done only by the code 2. However, Code 1 will not do it.
The reason is, as discussed in the beginning, code 1 and code 2 are function invocation expression and a function definition respectively. An event handler must be a function definition, it should not be a function invocation expression.
Additional information
Technically it is not an error to give a function invocation expression as an event handler. What will happen in this case is, since it is a function invocation expression given in the JSX, React system will evaluate or invoke that expression to get its return value. It is because only values are expected in a JSX. But in this case, the invocation does not return any value or it will return undefined as it has been defined. This undefined value will be ignored by React. Therefore the button will not get a handler.
However, the same function invocation expression if it returns functional object, then it would do the intend. By the way, this particular case is being discussed over here just for a demonstration purpose only and it does do not anything better than a direct handler. Please note, the below version of handleDelete returns a functional object.
const handleDelete = (id) => {
return () => {
const newUsers = users.filter((person) => person.id !== id);
setUsers(newUsers);
};
};
With the above version of handleDelete, now code 1 will also do the intend. What will happen now is, React will invoke the function during rendering, and this invocation will result a functional object. This functional object will be acting as the handler for click event, just like the code 2 does.
onClick={handleDelete(user.id)} // code 1
However code 2 will fail in this case, which you can guess by now. If code 2 also should work with the new version of handleDelete, then it needs to modify as below. Please take note of the two parenthesises suffixed in the statement. As you know, it is called an immediate invocation expression.
onClick={() => handleDelete(user.id)()} // code 2