Event Handling in React
Handling events in React is very similar to handling events on DOM elements, but there are some syntax differences and conceptual shifts due to React's cross-browser abstraction.
Synthetic Events
When you handle an event in React (like an onClick or onChange), you don't receive a native browser event. Instead, you receive a SyntheticEvent.
React wraps the native browser event into a SyntheticEvent to ensure that events have consistent properties and behaviors across all browsers. Under the hood, React delegates most events to the root of the document for performance optimization (event delegation).
Basic Event Handlers
React events are named using camelCase, rather than lowercase. With JSX, you pass a function as the event handler, rather than a string.
// HTML
// <button onclick="handleClick()">Click Me</button>
// React
export default function Button() {
const handleClick = () => {
alert("Button clicked!");
};
return (
<button onClick={handleClick}>
Click Me
</button>
);
}
Preventing Default Behavior
In plain HTML, you can sometimes return false to prevent default behavior (like submitting a form or following a link). In React, you must call preventDefault() explicitly on the event object.
export default function Form() {
const handleSubmit = (e) => {
e.preventDefault(); // Stops the page from refreshing
console.log("Form submitted securely!");
};
return (
<form onSubmit={handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
Passing Arguments to Event Handlers
Often, you'll need to pass an extra argument (like an ID) to an event handler. There are two common ways to do this:
1. Arrow Functions (Inline)
This is the most common approach. You create an anonymous arrow function inline that calls your handler with the required argument.
export default function List() {
const deleteItem = (id) => {
console.log("Deleting item with ID:", id);
};
return (
<ul>
{[1, 2, 3].map(id => (
<li key={id}>
Item {id}
<button onClick={() => deleteItem(id)}>Delete</button>
</li>
))}
</ul>
);
}
Note: While this creates a new function on every render, modern React handles this efficiently. You usually don't need to worry about performance unless rendering thousands of items.
2. Currying / Higher-Order Functions
You can write a function that returns another function.
export default function List() {
const deleteItem = (id) => (e) => {
console.log("Deleting item:", id);
console.log("Event target:", e.target);
};
return (
<button onClick={deleteItem(42)}>Delete Item 42</button>
);
}
Stopping Event Propagation
Just like standard DOM events, React events bubble up the tree. If you want to stop an event from reaching parent components, use e.stopPropagation().
export default function Card() {
const handleCardClick = () => {
console.log("Card clicked");
};
const handleButtonClick = (e) => {
e.stopPropagation(); // Prevents handleCardClick from firing
console.log("Button clicked");
};
return (
<div onClick={handleCardClick} style={{ padding: 20, border: '1px solid black' }}>
<p>Card Content</p>
<button onClick={handleButtonClick}>Action</button>
</div>
);
}