Events
You've built a button. Now it needs to actually do something when someone clicks it, save a form, open a menu, delete an item. React handles this the same way it handles everything else: through props. Instead of calling addEventListener like you did in the JavaScript events chapter, you pass a function directly to a prop on the element you want to listen on. The idea is the same, a function that runs when something happens, but the way you wire it up is a React pattern of its own.
Attaching a handler
function SaveButton() {
function handleClick() {
console.log('clicked')
}
return <button onClick={handleClick}>Save</button>
}Event props are named in camelCase, matching the event they listen for: onClick for clicks, onChange for a field's value changing, onSubmit for a form being sent. You write the prop on the element, and give it a function to run.
handleClick is defined inside the component, then passed to onClick. React calls it whenever the button is clicked. You're passing the function by name, handleClick. Calling it, handleClick(), would run it immediately, during render. You are handing React the function to run later, not running it yourself right now.
When you need details about what happened, React passes your handler an event object with the same familiar properties, target, preventDefault(), and so on, that you'd expect from addEventListener. Name a parameter to catch it, conventionally event:
function SearchBox() {
function handleChange(event) {
console.log(event.target.value)
}
return <input onChange={handleChange} />
}event.target is the element the event fired on, and event.target.value is the current text in the field. You only need to reach for the event object when a handler actually needs that information. A button's onClick often does not.
The most common mistake
Because the handler is a function you're handing to a prop, this is a mistake that catches nearly everyone at some point:
// Wrong: calls handleClick immediately, while the component renders
<button onClick={handleClick()}>Save</button>
// Right: passes the function itself, React calls it later, on click
<button onClick={handleClick}>Save</button>The parentheses are the whole difference. handleClick() runs the function right then, during render, and whatever it returns (usually undefined) is what ends up on onClick. handleClick hands React the function itself, to call whenever the click actually happens. If a handler seems to fire on its own the moment the page loads, this is almost always why.
Passing handlers down as props
A handler doesn't have to live in the same component as the element it's attached to. You can define it in a parent and pass it down to a child as a prop, the same way you'd pass any other value:
function SaveButton({ onSave }) {
return <button onClick={onSave}>Save</button>
}
function Form() {
function handleSave() {
console.log('saved')
}
return <SaveButton onSave={handleSave} />
}Form owns handleSave and passes it into SaveButton under the prop name onSave. SaveButton doesn't know or care what the function does, it wires it up to onClick. This is how a click on a small, reusable component ends up triggering logic that lives higher up in your app, closer to the state or data that logic needs.
Preventing the default behavior
Some events come with browser behavior attached, and submitting a form is the one you'll run into first. By default, submitting a form reloads the page, which throws away anything your component was doing. Call event.preventDefault() inside the handler to stop that:
function SignupForm() {
function handleSubmit(event) {
event.preventDefault()
console.log('form submitted')
}
return (
<form onSubmit={handleSubmit}>
<input type="email" />
<button type="submit">Sign up</button>
</form>
)
}Attach onSubmit to the <form> itself, not onClick to the button. That way pressing Enter inside the field submits the form too, not only clicking the button.
onClick and onChange, and you give them a function to run, not the result of running one. Write onClick={handleClick}, never onClick={handleClick()}. When a handler needs details about what happened, catch them with a parameter named event. Next up: Conditional rendering, where what a component returns starts to depend on the data it has.

