Topic 4.1
Responding to Events
In one line
You make a component react to the user by passing a function to an event prop such as onClick; React calls that function with an event object when the event happens, and the event bubbles up through parent handlers unless you stop it.
Think of it like this
A doorbell. When you build the house you wire the button to the bell, but the bell doesn't ring while you're wiring it. It rings later, each time a visitor presses it. An event handler is that wiring: you hand React a function now, and React calls it later, every time the click happens.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Event
- Something that happens on the page, like a click, a key press or a form submit.
- Event handler
- A function that runs when an event happens, like
handleClick. - camelCase
- Writing names with each word after the first starting with a capital:
onClick,onMouseEnter. - Inline handler
- A small arrow function written right inside the JSX:
onClick={() => setOpen(true)}. - Event object
- The object React passes to your handler, describing what happened (
e.type,e.target,e.key…). - SyntheticEvent
- React's wrapper around the browser's event, so events behave the same in every browser.
- Bubbling (propagation)
- An event travelling up from the element it started on to each parent in turn.
- stopPropagation
e.stopPropagation(): stops the event from reaching parent handlers.- preventDefault
e.preventDefault(): stops the browser's own action, such as reloading the page on a form submit.- Default action
- What the browser does by itself for an event: follow a link, submit a form, tick a checkbox.
Step by step
01Write a handler and pass it
Declare a function inside your component and pass it (no brackets) to the element's event prop. React stores it and calls it on every click.
function SaveButton() {
function handleClick() {
console.log("Saved!");
}
return <button onClick={handleClick}>Save</button>;
}02Read props and state inside the handler
A handler is a function inside the component, so it can see the component's props and state. That's how one AlertButton component can say different things.
function AlertButton({ message, children }) {
return <button onClick={() => console.log(message)}>{children}</button>;
}
<AlertButton message="Playing!">Play</AlertButton>
<AlertButton message="Uploading!">Upload</AlertButton>03Let the parent decide: handler props
A reusable Button shouldn't know what clicking means in every place it's used. It accepts an onClick prop and passes it down to the real <button>. The parent passes the behaviour in. Name such props onSomething; name the functions you write handleSomething.
function Button({ onClick, children }) {
return <button onClick={onClick}>{children}</button>;
}
function PlayButton({ movieName }) {
function handlePlayClick() {
console.log("Playing " + movieName);
}
return <Button onClick={handlePlayClick}>Play "{movieName}"</Button>;
}04Use the event object
React passes an event object as the first argument. e.target is where the event started; e.currentTarget is the element whose handler is running. For inputs, e.target.value is the current text (Phase 5).
function Search() {
function handleKeyDown(e) {
if (e.key === "Enter") console.log("search for", e.target.value);
}
return <input onKeyDown={handleKeyDown} placeholder="Press Enter" />;
}05Events bubble up the tree
A click on the button runs the button's handler first, then its parent's, then the grandparent's. Call e.stopPropagation() in the button's handler when the parent must not react.
06Stop the browser's own action
Submitting a form makes the browser reload the page by default, and a link click navigates. Call e.preventDefault() to cancel that and handle it yourself in JavaScript.
function Signup() {
function handleSubmit(e) {
e.preventDefault(); // no page reload
console.log("send the form with JavaScript");
}
return (
<form onSubmit={handleSubmit}>
<input name="email" />
<button>Sign up</button>
</form>
);
}Try it yourself
- 1
Add your own button to the toolbar
In the first example, add
<PlayButton movieName="Swades" />. Predict the new console line before running. You wrote no new handler: the samehandlePlayClickreads a different prop. - 2
Predict the bubbling order
In the second example, wrap the toolbar in
<main onClick={() => console.log("main got it")}>. Predict wheremain got itappears for Play and for Stop, then run. (After the toolbar for Play; not at all for Stop.) - 3
Pass an extra value
Write a list of three fruit buttons with
["apple", "mango", "kiwi"].map(...). Give eachonClick={() => console.log("picked", fruit)}. Why does this need an arrow function instead ofonClick={console.log("picked", fruit)}?
Code & diagrams
Nothing is logged while React renders: handlers run only when a click happens. The code at the bottom clicks all three buttons once; click them yourself too.
Preview
Console
Nothing logged yet.Expected console output
Playing Lagaan
App decides: uploading!
Inline handler ranPlay: capture (top-down) runs first, then the button, then the bubble up to the toolbar. Stop: capture still runs (it happens before the button), but `stopPropagation` blocks the bubble. Click the orange area itself: only the toolbar logs.
Preview
Console
Nothing logged yet.Expected console output
capture: the toolbar sees it first
Play: click target BUTTON currentTarget BUTTON
bubble: the toolbar got a click from Play
capture: the toolbar sees it first
Stop: handled here only`onSubmit` goes on the `<form>`, not on the button, so pressing Enter in the input submits too. Remove a `preventDefault()` line and run again: the preview reports the submit or the link instead.
Preview
Console
Nothing logged yet.Expected console output
Signing up asha@example.com | default prevented: true
Link click handled in JavaScriptBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Call the setter instead of passing a function
In a counter, write <button onClick={setCount(count + 1)}> (no arrow function).
Break #2
Pass a string like in HTML
Write <button onClick="alert('hi')"> the way old HTML does.
Break #3
Call a handler that only logs
Write onClick={sayHi()} where sayHi only does console.log("hi").
Myth vs fact
Myth
onClick={handleClick()} and onClick={handleClick} are the same.
Fact
The first calls the function during render and passes its result. The second passes the function for React to call later. Only the second runs on click.
Myth
Inline arrow functions in JSX are bad for performance.
Fact
Creating a small function per render is cheap. It only matters when the child is memoized and compares props (Phase 16), and the React Compiler handles even that for you.
Myth
React adds a listener to every element with an onClick.
Fact
Since React 17, React attaches one listener per event type to the root container and dispatches to your handlers itself (event delegation). Your code still behaves as if each element had its own.
Myth
stopPropagation also stops the browser's default action.
Fact
No. stopPropagation stops parents' handlers; preventDefault stops the browser's default. A link with only stopPropagation still navigates.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
React 17 moved its event listeners from
documentto the root container, so several React versions (or React and other code) can live on one page without fighting overstopPropagation. React 17 also stopped bubblingonScroll, matching the browser. - ▸
There is no event pooling any more: before React 17, SyntheticEvent objects were reused and their fields cleared after the handler, so reading
e.targetin asetTimeoutfailed. Since React 17 you can keep and read the event later. - ▸
Not every user action deserves
stopPropagation: it hides the event from everything above, including analytics and "click outside to close" code. Prefer checkinge.targetin the parent, or pass a handler down so the parent decides. - ▸
Accessibility: put
onClickon a real<button>, not on a<div>. A button is focusable, works with Enter and Space and is announced by screen readers; a<div onClick>needsrole,tabIndexand key handlers to come close (see the /html course on accessible controls).
Remember this
- 1
An event is something that happens in the page: a click, a key press, a form being submitted, the mouse moving over an element. An event handler is a function that runs when that event happens. In React you attach one by passing it as a prop to a built-in element:
<button onClick={handleClick}>. The prop names are the browser event names in camelCase (each word after the first starts with a capital):onClick,onChange,onSubmit,onKeyDown,onMouseEnter,onFocus,onBlur. - 2
Pass a function, don't call it.
onClick={handleClick}hands React the function itself.onClick={handleClick()}(with brackets) calls it straight away, while React is rendering, and gives React whatever it returned (usuallyundefined). The same goes for inline code:onClick={() => setCount(count + 1)}is a function React can call later;onClick={setCount(count + 1)}runs the setter during render, which asks for another render, which runs it again: React stops that loop with an error. - 3
You can write handlers two ways. A named handler is a function declared inside the component, by convention called
handle+ event:handleClick,handleSubmit,handleNameChange. An inline handler is an arrow function written right in the JSX:onClick={() => alert("Hi")}. Inline is handy for one line or for passing an extra value:onClick={() => handleDelete(item.id)}. Because handlers are defined inside the component, they can read its props and state. - 4
Handlers can be passed as props. A parent often decides what a click should do and gives the child a function to call. By convention a prop that receives a handler is named
on+ something:<Button onClick={...}>,<PlayButton onPlay={...}>,<Toolbar onUploadImage={...}>. Built-in elements like<button>only understand real browser event names, but your own components can name their event props anything, so pick names that describe what happened in your app (onSelectSong, notonClick2). - 5
React calls your handler with an event object (usually named
eorevent). It is a SyntheticEvent: React's wrapper around the browser's event, with the same properties on every browser. Useful parts:e.type("click"),e.target(the element where the event started, maybe a deep child),e.currentTarget(the element whose handler is running now),e.keyfor keyboard events,e.target.valuefor inputs, ande.nativeEventfor the browser's original event. - 6
Propagation: most events bubble. After a button's
onClickruns, the click travels up to its parent, grandparent and so on, running each ancestor'sonClicktoo.e.stopPropagation()stops the event going further up. Separately, some events have a default action the browser does by itself: a form submit reloads the page, a link click navigates.e.preventDefault()cancels that default action. The two are unrelated: one stops parents hearing the event, the other stops the browser's own behaviour. (There is also a capture phase that runs top-down before bubbling; use it withonClickCapture.) All events bubble in React exceptonScroll.
Explain it without notes
What is the difference between onClick={handleClick} and onClick={handleClick()}?
What are the naming conventions for handlers and handler props, and why do they help?
Explain event propagation in React and how stopPropagation and preventDefault differ.
What is e.target versus e.currentTarget?
Practice
Make a ColorSwitch component that takes an onChangeColor prop. Its button must change the page colour (through the parent) but must not trigger the parent div's own onClick that counts clicks.
Write a form with one input name that logs Hello, <name>! on submit without reloading the page.
Trade-offs
- ↔
Inline handlers keep short logic next to the markup; named handlers are easier to read, test and reuse when the logic grows past a line or two.
- ↔
stopPropagationis quick but invisible to the code above; a handler prop that lets the parent decide is more explicit and easier to debug.
Done when you can
I can attach a handler with
onClickand pass the function without calling it.I can name handlers
handleXand handler propsonX.I can pass a handler from a parent to a child as a prop.
I can read
e.target,e.currentTargetande.keyfrom the event object.I can explain bubbling and use
stopPropagationandpreventDefaultcorrectly.