2.4 Handling Events in React
← Back to Chapter 2: React Fundamentals
Handling events in React is syntactically very similar to handling events in the DOM, but with key architectural differences: event names are camelCased, you pass function references rather than strings, and React wraps native events in a cross-browser SyntheticEvent system.
1. Syntax: Passing Function References
In plain HTML, event listener attributes take a string to be evaluated. In React JSX, you pass a function reference:
// Plain HTML:
// <button onclick="handleClick()">Click Me</button>
// React JSX:
function Button() {
function handleClick() {
alert("Button clicked!");
}
// Pass function reference:
return <button onClick={handleClick}>Click Me</button>;
}
Never invoke the function directly inside the JSX attribute:
// ❌ WRONG: handleClick() runs immediately on every render!
<button onClick={handleClick()}>Click Me</button>
// ✅ CORRECT: Passes the function to be called on click
<button onClick={handleClick}>Click Me</button>
2. Passing Arguments to Event Handlers
When an event handler requires arguments, wrap it in an inline arrow function:
function ItemList({ items, onDelete }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>
{item.name}
{/* Inline arrow function passes item.id when clicked */}
<button onClick={() => onDelete(item.id)}>Delete</button>
</li>
))}
</ul>
);
}
3. The SyntheticEvent Object
Event handlers receive an instance of SyntheticEvent, a cross-browser wrapper around the browser's native DOM event (e.nativeEvent). It shares the same interface as the native event (stopPropagation(), preventDefault()), but guarantees identical behavior across Chrome, Safari, Firefox, and Edge.
function SearchForm() {
function handleSubmit(event) {
// Prevents browser from reloading the page on form submit
event.preventDefault();
console.log("Submitting via AJAX...");
}
return (
<form onSubmit={handleSubmit}>
<input type="text" name="query" />
<button type="submit">Search</button>
</form>
);
}
React doesn't actually attach event handlers to every individual button in the DOM. Under the hood, React attaches a single listener to the root container (#root) and delegates events down (Event Delegation).
4. Stopping Event Propagation
If a child element is nested inside a clickable parent container, clicking the child triggers both handlers due to event bubbling. Call e.stopPropagation() to stop bubbling:
function Card({ onCardClick, onBookmark }) {
return (
<div className="card" onClick={onCardClick}>
<h3>Course Overview</h3>
<button
onClick={(e) => {
e.stopPropagation(); // Prevents onCardClick from firing!
onBookmark();
}}
>
Bookmark
</button>
</div>
);
}
5. Summary Checklist
- Event names in React use camelCase (
onClick,onSubmit,onKeyDown,onChange). - Pass a function reference (
onClick={handleClick}) rather than invoking the function (onClick={handleClick()}). - Use inline arrow functions (
onClick={() => handleClick(id)}) to pass custom parameters. - Always call
e.preventDefault()inside form submit handlers to prevent page reload. - Use
e.stopPropagation()to prevent nested click events from bubbling up to parent containers.