javascript - How to Properly Implement Arrow Function in ReactJS? - Stack Overflow

admin2025-05-02  0

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?

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?

Share Improve this question edited Jan 2 at 14:44 armel 2,5801 gold badge24 silver badges30 bronze badges asked Jan 2 at 12:33 Mai OsamaMai Osama 114 bronze badges 2
  • In short: {() => handleDelete(user.id)} fires up and calls the functions handleDelete() when the button is clicked. On the other hand {handleDelete(user.id)} is the same as assigning the onClick property the return value of the handleDelete() function which - in this case - returns nothing and undefined will be assigned. – Sarkis Commented Jan 2 at 14:03
  • duplicate: How can I pass other arguments to event handler in React?. – pilchard Commented Mar 30 at 15:44
Add a comment  | 

3 Answers 3

Reset to default 2

One applies the function, ie runs the function an evaluates to the function's return value -

handleDelete(user.id)

The other is a function waiting to be called -

() => handleDelete(user.id)

Which can be seen the same as -

function() {
  handleDelete(user.id)
}

onClick expect a function to call when the click happens, which explains why the second one works. The first is the result of a function call, not a function itself.


Worth noting, onClick passes an event to the function that contains many information our handler can respond to. In the second example, the nullary () => ... is used and the event data is ignored. This is the same as (event) => ... where event is not used. Now see what happens when we colocate the event with the handler -

function DeleteButton(props) {

  const handleDelete = id => event => // ✅
    setUsers(users => users.filter(user => user.id != id))

  return (
    <button
      children="delete"
      onClick={handleDelete(props.id)} // ✅
    />
  )
}

Now it works because handDelete(props.id) returns a function (event => setUsers(...)), which onClick is expecting.

Another thing you may notice is we didn't have to pass users to handleDelete. This is possible because we used an updater function for the setUsers call, which is passed a copy of the previous state.


This knowledge allows us to easily remove complex logic from your components. Imagine a separate Users module -

// users.js

export const removeById = id => users =>
  users.filter(u => u.id !== id)

Now when writing our component, we can keep things more high level.

import * as Users from "./users" // ✅

function DeleteButton(props) {
  const handleDelete = id => event =>
    setUsers(Users.removeById(id)) // ✅
  return (
    <button
      children="delete"      
      onClick={handleDelete(props.id)} // ✅
    />
  )
}

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

Case1: onClick={handleDelete(user.id)} -

React instantly executes handleDelete(user.id) when the component is rendered, but since handleDelete doesn't return anything at first, the function call's outcome is undefined. Afterwards, it becomes into -

onClick={undefined}

Case2: onClick={() => handleDelete(user.id)} -

The arrow function takes some time to perform. Rather, it is a reference to a function that will be called when the button is clicked. The arrow function is triggered when the button is clicked, and it then calls handleDelete(user.id) with the appropriate id.

转载请注明原文地址:http://anycun.com/QandA/1746120092a91945.html