Loading

Quipoin Menu

Learn • Practice • Grow

react / Passing Arguments to Events
tutorial

Passing Arguments to Events

Often, you need to pass additional information to your event handler. For example, when deleting an item from a list, you need to know which item to delete. React provides several ways to pass arguments to event handlers.

The Challenge

You might try something like this, but it won't work as expected:
function ItemList() {
  const [items, setItems] = useState(['Apple', 'Banana', 'Orange']);

  <!-- This won't work as expected! -->
  function handleDelete(item) {
    setItems(items.filter(i => i !== item));
  }

  return (
    <ul>
      {items.map(item => (
        <li key={item}>
          {item}
          <button onClick={handleDelete(item)}>Delete</button> <!-- ❌ This calls the function immediately! -->
        </li>
      ))}
    </ul>
  );
}

The problem: `handleDelete(item)` is called immediately when the component renders, not when the button is clicked. This happens because we're invoking the function, not passing it.

Solution 1: Arrow Function Wrapper
<button onClick={() => handleDelete(item)}>Delete</button>

This creates a new function that, when called, calls `handleDelete(item)`. This works perfectly and is the most common approach.

Solution 2: Function that Returns a Function
function ItemList() {
  const [items, setItems] = useState(['Apple', 'Banana', 'Orange']);

  function createDeleteHandler(itemToDelete) {
    return function() {
      setItems(items.filter(i => i !== itemToDelete));
    };
  }

  return (
    <ul>
      {items.map(item => (
        <li key={item}>
          {item}
          <button onClick={createDeleteHandler(item)}>Delete</button>
        </li>
      ))}
    </ul>
  );
}

This approach is less common but can be useful for complex handlers.

Passing the Event Object Along with Arguments

Sometimes you need both the event object and your custom arguments. You can do this with an arrow function:
function TodoItem({ id, text, onDelete }) {
  function handleDelete(event) {
    console.log('Delete button clicked at', event.clientX, event.clientY);
    onDelete(id);
  }

  return (
    <li>
      {text}
      <button onClick={(e) => handleDelete(e)}>Delete</button>
    </li>
  );
}

Example: Real-World Usage
function ShoppingCart() {
  const [cart, setCart] = useState([
    { id: 1, name: 'Laptop', price: 999 },
    { id: 2, name: 'Mouse', price: 25 },
    { id: 3, name: 'Keyboard', price: 75 }
  ]);

  function handleRemove(itemId, event) {
    <!-- Prevent default if needed (e.g., if this is inside a form) -->
    event.preventDefault();
    setCart(cart.filter(item => item.id !== itemId));
  }

  function handleUpdateQuantity(itemId, newQuantity, event) {
    event.preventDefault();
    setCart(cart.map(item =>
      item.id === itemId ? { ...item, quantity: newQuantity } : item
    ));
  }

  return (
    <div>
      {cart.map(item => (
        <div key={item.id}>
          <span>{item.name} - ${item.price}</span>
          <input
            type="number"
            value={item.quantity || 1}
            onChange={(e) => handleUpdateQuantity(item.id, parseInt(e.target.value), e)}
          />
          <button onClick={(e) => handleRemove(item.id, e)}>Remove</button>
        </div>
      ))}
    </div>
  );
}

Two Minute Drill

  • To pass arguments to event handlers, use an arrow function wrapper: `onClick={() => handler(arg)}`.
  • This avoids the function being called immediately during render.
  • You can access both the event and custom arguments in the arrow function.
  • Common use cases: deleting an item from a list, updating a specific item, handling form inputs with IDs.
  • The arrow function creates a new function on each render, but this is usually fine. For performance-critical situations, you can use `useCallback`.

Need more clarification?

Drop us an email at career@quipoinfotech.com