
Passing vs. Calling Functions in React Event Handlers
A common React mistake is accidentally calling a function immediately instead of passing it as an event handler. This can cause unexpected behavior in your application.
The Problem
// ❌ Wrong: Function is called immediately during render
<button onClick={handleClick()}>Click Me</button>This executes handleClick when the component renders rather than when the button is clicked.
Correct Approaches
1. Pass Function Reference (Recommended)
// ✅ Correct: Pass the function reference
<button onClick={handleClick}>Click Me</button>2. Use Arrow Function for Parameters
// ✅ Correct: Wrap in arrow function when you need to pass arguments
<button onClick={() => handleClick(id)}>Click Me</button>3. Bind Function for Parameters (Alternative)
// ✅ Correct: Bind parameters (less common in modern React)
<button onClick={handleClick.bind(null, id)}>Click Me</button>Key Differences
| Approach | When Called | Arguments | Performance | 
|---|---|---|---|
| onClick={handleClick} | On click | Event object | Best | 
| onClick={() => handleClick(id)} | On click | Custom args | Good | 
| onClick={handleClick()} | On render | N/A | Bad | 
Common Use Cases
Basic Click Handler
function handleClick(event) {
  console.log('Clicked!', event);
}
return <button onClick={handleClick}>Click</button>;With Parameters
function deleteItem(id) {
  // Delete logic
}
return (
  <button onClick={() => deleteItem(item.id)}>
    Delete
  </button>
);Event Object Access
function handleClick(event) {
  event.preventDefault();
  console.log(event.target);
}
return <a href="#" onClick={handleClick}>Link</a>;Performance Considerations
- Avoid creating new functions in render:
   // ❌ Creates new function on each render
   <button onClick={() => handleClick(id)}>Click</button>
   // ✅ Better: Use useCallback for frequently re-rendered components
   const memoizedHandler = useCallback(() => handleClick(id), [id]);
   <button onClick={memoizedHandler}>Click</button>- For lists, pass data attributes instead:
   {items.map(item => (
     <button 
       key={item.id}
       onClick={handleItemClick} 
       data-id={item.id}  // Access via event.target.dataset.id
     >
       {item.name}
     </button>
   ))}Debugging Tips
If your handler is executing immediately:
- Check for accidental parentheses ()
- Verify you’re not invoking the function during render
- Use console.log to see when the function is called
TypeScript Example
interface ButtonProps {
  onAction: (id: number) => void;
  id: number;
}
const Button: React.FC<ButtonProps> = ({ onAction, id }) => (
  <button onClick={() => onAction(id)}>Action</button>
);Remember: React event handlers expect a function reference, not a function call. Only use parentheses when you intentionally want to call the function during render.
