Responding to events
Make your components react to clicks, typing and other user actions with event handlers.
Until now, your components have been like posters: they look nice, but nothing happens when you touch them. Real apps respond to people. You click a button and a menu opens. You type in a box and suggestions appear.
In React, you respond to the user with event handlers. These are your own functions that React calls when something happens, such as a click, a key press or a form submit. Today starts here, because every interactive feature you build this week begins with an event.
Your first event handler
Here is a button that does something when you click it. Click it and watch the console panel under the preview.
There are three steps:
- Declare a function inside your component. Here it is
handleClick. - Put your logic inside it. Here it logs a message.
- Pass the function to the button as the
onClickprop.
The name onClick is a built-in prop that React understands on HTML-like elements such as <button>. Other common ones are onChange, onSubmit, onMouseEnter, onFocus and onKeyDown. They all follow the same pattern: on plus the event name in camelCase.
By convention, event handler functions are named handle plus the event: handleClick, handleChange, handleSubmit. React doesn't require this, but it makes your code much easier to scan.
Inline handlers
For a short handler, you can write the function right inside the JSX with an arrow function. These two buttons do the same thing:
function handleClick() {
console.log('Clicked');
}
<button onClick={handleClick}>Named</button>
<button onClick={() => console.log('Clicked')}>Inline</button>Use the named version when the logic is more than a line or two. Use the inline version for tiny things, or when you need to pass an argument (you'll see that below).
Handlers can read props
Because an event handler is declared inside your component, it can see that component's props. That lets you make one reusable button that behaves differently depending on what you pass in.
Passing handlers as props
Often the parent knows what should happen, while the child only knows that a click happened. In that case the parent passes a function down as a prop, and the child attaches it to its button.
For your own components, you can name these props anything. The convention is to start them with on, like onPlay or onDelete, so they read like built-in events.
Notice the second button. handleDelete needs an argument, so the parent wraps it in an arrow function: () => handleDelete('holiday.png'). This is the pattern you'll use in the Reading List to say which book was clicked.
The event object
React passes an event object as the first argument to every handler. By convention it's called e. It describes what happened: which element was involved, which key was pressed, and so on.
The most useful property for now is e.target, the element where the event happened. For a text input, e.target.value is the text currently in the box.
In React, onChange fires on every keystroke, not only when the input loses focus as in plain HTML. That's what makes live search boxes and form validation easy. You'll lean on this in the forms lesson.
Propagation and default behavior
Events in the browser bubble (also called propagate). When you click a button inside a <div>, the click fires on the button first, then on the <div>, then on its parent, all the way up. Usually that's harmless, but sometimes a parent and child both have click handlers and you only want one to run.
Call e.stopPropagation() to stop the event from going further up. Try clicking the card body, then each button, with and without the fix.
Some events also have a default behavior in the browser. The big one is submitting a <form>: by default the browser reloads the whole page. Call e.preventDefault() to stop that.
function handleSubmit(e) {
e.preventDefault(); // stay on the page
console.log('Form submitted');
}
<form onSubmit={handleSubmit}>
<input />
<button type="submit">Send</button>
</form>These two are easy to mix up. stopPropagation() stops parent handlers from running. preventDefault() stops the browser's built-in action. They are unrelated.
Deep diveCan event handlers have side effects?
Yes, and that is exactly what they are for. Rendering must be pure: a component should only calculate JSX from its props and state, as you learned on Day 2. Event handlers are different. They run when the user does something, not during rendering, so they are the right place to change things: update state, log, send a request, start an animation.
When you are not sure where some code with a side effect should go, an event handler is usually the first place to look.
Fix the broken button
This button should log "Saved!" when clicked, but instead it logs as soon as the page loads, and clicking does nothing. Open the console, find the bug and fix it.
Show solution
The code called handleSave() during rendering and passed its return value (undefined) to onClick. Remove the parentheses so React receives the function itself:
<button onClick={handleSave}>Save</button>You might see "Saved!" logged twice on load in the broken version. That's React's development-only Strict Mode rendering components twice to help you find bugs like this one.
A color-picker toolbar
Build a ColorButton component that takes a color prop and an onPick prop. When clicked, it should call onPick with its color. In App, render three of them (red, green, blue) and log the picked color.
Show solution
The child doesn't know what "picking" means. It only knows its own color and calls onPick(color) when clicked. The parent decides what to do with it. This split between "something happened" (child) and "here's what to do about it" (parent) is the pattern you'll use for the delete and status buttons in the Reading List.
Which of these runs the handler only when the button is clicked?
A Delete button sits inside a clickable card. Clicking Delete also opens the card. What should the Delete handler call?
Day 3 progress