skip to Main Content

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?

2

Answers


  1. 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)} // ✅
        />
      )
    }
    
    Login or Signup to reply.
  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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search