Passing Event Handlers as Props #45
📖 Introduction
We've learned how to make components interactive by defining event handler functions right inside them. But what if you want to create a truly reusable component, like a generic Button
, whose behavior changes depending on where it's used?
This article explores a fundamental pattern in React for creating reusable components: passing event handlers as props. This allows a parent component to define what should happen, while the child component only knows when it should happen.
📚 Prerequisites
Before we begin, please ensure you have a solid grasp of the following concepts:
- React Props: You must be comfortable passing props from a parent to a child.
- React Event Handlers: You should know how to define and attach an
onClick
handler. - JavaScript Functions as Values: Understanding that functions can be passed around in variables and props just like any other data type.
🎯 Article Outline: What You'll Master
In this article, you will learn:
- ✅ The "Why": Understanding the motivation for creating reusable components with customizable behavior.
- ✅ The Pattern: How to define an event handler in a parent and pass it as a prop to a child.
- ✅ Creating a Generic Component: Building a reusable
Button
component that accepts anonClick
prop. - ✅ Naming Conventions: The standard convention for naming your event handler props.
🧠 Section 1: The Core Concept: Separating "What" from "When"
Imagine you are building a UI with many buttons. One button plays a movie, another uploads a file, and a third saves a form. The appearance of these buttons might be identical (the same CSS classes, the same structure), but their behavior is completely different.
Instead of creating three separate button components, it's much more efficient to create one generic Button
component. This Button
component will know how to look and feel like a button, but it won't know what to do when it's clicked.
We can then tell it what to do by passing a function in as a prop. This separates the concerns:
- Child Component (
Button
): Knows when the event happens (the user clicks it). - Parent Component (
Toolbar
): Knows what should happen when the event occurs (play a movie, upload an image).
💻 Section 2: A Practical Example: A Reusable Button
Let's build a Toolbar
that uses a single, reusable Button
component for two different actions.
Step 1: Create the Generic Button
Component
This component's only job is to look like a button and to call whatever function it receives in its onClick
prop when it is clicked.
// Button.jsx
import React from 'react';
// This is a generic, reusable button.
// It accepts an 'onClick' function and 'children' as props.
function Button({ onClick, children }) {
return (
<button onClick={onClick}>
{children}
</button>
);
}
export default Button;
Notice that this component is "dumb." It has no idea what "playing a movie" or "uploading an image" means. It only knows that when it's clicked, it needs to call the onClick
function it was given.
Step 2: Use the Button
in a Parent Component
Now, the parent Toolbar
component can use our generic Button
and provide the specific logic for each instance.
// Toolbar.jsx
import React from 'react';
import Button from './Button';
export default function Toolbar() {
// Define the specific logic for the first button
function handlePlayClick() {
alert('Playing movie!');
}
return (
<div>
{/* Pass the specific handler to the first button */}
<Button onClick={handlePlayClick}>
Play Movie
</Button>
{/* Pass a different handler (inline) to the second button */}
<Button onClick={() => alert('Uploading image!')}>
Upload Image
</Button>
</div>
);
}
Code Breakdown:
handlePlayClick
: The parentToolbar
defines a function that contains the logic for what should happen when the "Play Movie" button is clicked.<Button onClick={handlePlayClick}>
: TheToolbar
passes thehandlePlayClick
function down to theButton
component as a prop namedonClick
.<Button onClick={() => ...}>
: For the second button, we pass a different function inline.- Inside the
Button
component, theonClick
prop it receives is wired up to the actual<button>
element'sonClick
event.
This pattern is incredibly powerful. It allows you to create a library of beautifully styled, reusable components (Button
, Input
, Card
, etc.) that are completely decoupled from your application's business logic.
🛠️ Section 3: Naming Event Handler Props
The built-in JSX elements like <button>
have specific event prop names like onClick
. However, when you create your own components, you can name your props whatever you want.
While <Button onClick={...}>
is common, you could name the prop based on a more specific interaction.
// App.jsx
function App() {
return (
<Toolbar
onPlayMovie={() => alert('Playing!')}
onUploadImage={() => alert('Uploading!')}
/>
);
}
// Toolbar.jsx
function Toolbar({ onPlayMovie, onUploadImage }) {
return (
<div>
{/* The Button component still expects an 'onClick' prop */}
<Button onClick={onPlayMovie}>Play Movie</Button>
<Button onClick={onUploadImage}>Upload Image</Button>
</div>
);
}
The Convention: By convention, event handler props should:
- Start with
on
. - Be followed by a capital letter.
- Describe the interaction (e.g.,
onPlayMovie
,onUploadImage
,onSmash
).
This makes the code highly readable from the parent's perspective. The App
component doesn't care that Toolbar
will eventually use these functions for an onClick
event; it just knows it's providing handlers for specific, high-level actions.
💡 Conclusion & Key Takeaways
Passing event handlers as props is a fundamental pattern for building reusable and decoupled components in React. It allows you to separate a component's presentation and generic behavior from the specific application logic it needs to trigger.
Let's summarize the key takeaways:
- Functions are Props: You can pass functions from a parent to a child just like any other prop.
- Create Reusable Components: This pattern is the key to creating generic components like buttons, inputs, and modals that can be used in many different contexts.
- Parent Defines the "What": The parent component is responsible for defining the specific logic that should run.
- Child Defines the "When": The child component is responsible for calling the handler at the appropriate time (e.g., on a click).
- Follow Naming Conventions: Name your event handler props starting with
on
to make their purpose clear.
Challenge Yourself:
Create a generic DeletableListItem
component. It should accept two props: text
(the content to display) and onDelete
(a function). The component should render the text and a "Delete" button. When the button is clicked, it should call the onDelete
function that was passed in from the parent.
➡️ Next Steps
You now understand how to create interactive components and how to make them reusable by passing handlers as props. In the next article, "Event Object and its Properties", we will look more closely at the event object itself and how to read information from it, such as the value of an input field.
Thank you for your dedication. Stay curious, and happy coding!
glossary
- Passing a Handler: The act of providing a function as a prop from a parent component to a child component.
- Decoupling: The practice of separating components so that they can be developed, modified, and reused independently of each other. Passing event handlers as props is a form of decoupling.