Passing Arguments to Handlers

Wrap in an Arrow When You Need Extra Data

Passing Arguments to Handlers

How to pass extra information (like an item id) into an event handler without breaking everything.

3 min read Level 1/5 #react#events#handlers
What you'll learn
  • Pass arguments to handlers
  • Avoid the "calling on render" pitfall

A handler usually needs the event object — (e) => …. But sometimes you also want extra data: which item was clicked, which row to delete. There are two clean ways.

1. Arrow Wrapper

Wrap your function in an inline arrow and pass the args you want:

function List({ items, onDelete }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>
          {item.name}
          <button onClick={() => onDelete(item.id)}>x</button>
        </li>
      ))}
    </ul>
  );
}

The arrow creates a brand-new function on every render — usually fine in lists. (If a render-performance audit later flags it, you’ll use useCallback.)

2. Curry a Handler Factory

When you call the same pattern many times, factor out a maker:

function List({ items, onDelete }) {
  const makeDelete = id => () => onDelete(id);

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>
          {item.name}
          <button onClick={makeDelete(item.id)}>x</button>
        </li>
      ))}
    </ul>
  );
}

Same outcome, slightly more explicit shape.

Keeping the Event Object Too

If you need BOTH extra args and the event, take both in the arrow:

<button onClick={e => handleClick(e, item.id)}>x</button>

The Anti-Pattern To Avoid

// ✗ Calls onDelete(item.id) on every render — fires immediately, infinite loop if it sets state
<button onClick={onDelete(item.id)}>x</button>

// ✓ Wrap in an arrow so it fires only on click
<button onClick={() => onDelete(item.id)}>x</button>

Up Next

You’ve reacted to clicks. Now React needs to remember things — useState.

useState →