Skip to main content

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 an onClick 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:

  1. handlePlayClick: The parent Toolbar defines a function that contains the logic for what should happen when the "Play Movie" button is clicked.
  2. <Button onClick={handlePlayClick}>: The Toolbar passes the handlePlayClick function down to the Button component as a prop named onClick.
  3. <Button onClick={() => ...}>: For the second button, we pass a different function inline.
  4. Inside the Button component, the onClick prop it receives is wired up to the actual <button> element's onClick 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.

Further Reading