React Events
React lets you respond to user interactions like clicks, typing, and form submissions by attaching event handler functions directly to JSX elements.
Wiring Up onClick
In React, you attach event handlers to elements using camelCase attributes such as onClick, onChange, and onSubmit. Unlike HTML's string-based onclick="..." attributes, React expects an actual JavaScript function — a reference, not a function call. Passing myFunction() instead of myFunction runs the function immediately during render instead of waiting for the click.
A Button That Counts Clicks
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<p>You clicked {count} times</p>
<button onClick={handleClick}>Click me</button>
</div>
);
}
export default Counter;Passing Arguments to Handlers
Sometimes a handler needs extra information, like which item in a list was clicked. Since onClick expects a function reference, you can't write onClick={handleDelete(id)} directly — that calls handleDelete immediately during render. Instead, wrap the call in an inline arrow function, which React will invoke only when the event actually fires.
Deleting an Item by Id
import { useState } from 'react';
function TodoItem({ id, text, onDelete }) {
return (
<li>
{text}
<button onClick={() => onDelete(id)}>Delete</button>
</li>
);
}
function TodoList({ items, onDelete }) {
return (
<ul>
{items.map((item) => (
<TodoItem key={item.id} {...item} onDelete={onDelete} />
))}
</ul>
);
}
function App() {
const [items, setItems] = useState([
{ id: 1, text: 'Buy milk' },
{ id: 2, text: 'Walk the dog' },
{ id: 3, text: 'Write React lesson' },
]);
function handleDelete(id) {
setItems((current) => current.filter((item) => item.id !== id));
}
return <TodoList items={items} onDelete={handleDelete} />;
}
export default App;Reading the Event Object
Every handler receives a SyntheticEvent as its first argument — a wrapper React builds around the browser's native event so it behaves consistently across browsers. You can read properties like event.target.value, call event.preventDefault(), or stop propagation with event.stopPropagation(), exactly as you would with a native DOM event.
Combining an Event and a Value
import { useState } from 'react';
function SearchBox({ onSearch }) {
function handleChange(event) {
onSearch(event.target.value);
}
return (
<input
type="text"
placeholder="Search..."
onChange={handleChange}
/>
);
}
function App() {
const [query, setQuery] = useState('');
return (
<div>
<SearchBox onSearch={setQuery} />
<p>Searching for: {query}</p>
</div>
);
}
export default App;- Name handlers with a handle prefix, like handleClick or handleSubmit, so their purpose is obvious at a glance.
- Extract inline arrow functions into named functions once the logic grows past a single line.
- Never call the handler directly in JSX — pass the reference, or wrap it in an arrow function if arguments are needed.
- Destructure only the event fields you need (event.target.value) rather than storing the whole event object in state.
Exercise: React Events
How are event handler attribute names written in JSX, such as for a click event?