Skip to main content

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>;
}
Critical Pitfall: Calling vs Passing Functions

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>
);
}
Event Delegation

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.