You can give React components props, which are like inputs to give your component some extra information (or functions!) to work with.
You can pass all sorts of props to your components. Strings. Numbers. Booleans. Objects. And, as you have probably guessed from the title of this blog post... functions!
<YourComponent
aString="amazing"
aBoolean={true}
aNumber={3}
anObject={{ key: "value" }}
aFunction={() => { return "I'm a function!" }}
/>
Passing functions is one of the more useful props because you can get your component to do something. And you can use the same component over and over, but give it a different function so that each time you use it, it does something different.
Pretty cool!
In the example above, I'm passing an inline function. But that's not the only way to pass a function as a prop.
So let's look at some more options:
- As a function
yourProp={yourFunction}
- As an inline function
yourProp={() => alert("The function has been called!")}
- As an inline function with parameters
yourProp={() => yourFunction(id, name)}
1. As a function
You can pass a function as a prop by naming the function in your component and then giving the function as the prop value. Like this:
// the function
function yourFunction() {
alert("The function has been called!");
};
return <YourComponent action={yourFunction} />
Whatever you do, don't call the function when you pass it as a prop:
// the function
function yourFunction() {
alert("The function has been called!");
};
// ❌ don't call the function in the prop
return <YourComponent action={yourFunction()} />
That won't work.
Every time your component renders, the function will be called, and because the prop has changed, the component will render again, calling the function again... and that's what we call an infinite loop!
Just pass the function name, so your component can call it when it is good and ready (and not a moment sooner!).
Here's how you could useEffect
to call the function when the component mounts.
import React from 'react';
function ParentComponent(props) {
// the function
function yourFunction() {
alert("The function has been called!");
};
return <ChildComponent action={yourFunction} />
};
function ChildComponent({action}) {
// call the function once on mount
React.useEffect(() => {
action();
}, []);
return "I'm the child component!";
};
The function is defined in the parent component, passed as a prop to the child component, and called by the child component.
A real-world example of this could be an onClick
handler passed to a Button
component.
Let's imagine we have a reusable Button
component we use throughout our React app for consistent styling.
<Button>Click Me!</Button>
Each time we use that Button
we want it to look the same (or similar), but each button might do something different.
For example, one button might submit a form, another might "like" a post, and another might open a modal... you get the idea!
Here's how our Button
component might be coded*:
*This is a very simplified version, just showing how to pass props to the button!
function Button(props) {
return (
<button {...props} />
);
};
All of the props
we send to our Button
component are given to the button, with{...props}
, so we can pass a function for the onClick
handler.
Alternatively, you can deconstruct props
, and pass the onClick
directly in the component like this:
function Button({ children, onClick }) {
return (
<button onClick={onClick}>{children}</button>
);
};
Whichever way you choose to pass that onClick
handler - with{...props}
or onClick
- it ends up on the button.
So now let’s pass our function!
function Parent() {
// the function
function yourFunction() {
alert("The function has been called!");
};
return (
<Button onClick={yourFunction}>Click Me!</Button>
)
};
Whenever you click the button, your function gets called!
<div id="app"></div>
// button function Button(props) { return ( <button className="p-3 rounded bg-gray-200" {...props} /> ); }; // app function App() { // the function function yourFunction() { alert("The function has been called!"); }; return ( <div className="flex flex-col w-full min-h-screen items-center justify-center p-5"> <Button onClick={yourFunction}>Click Me!</Button> </div> ) } ReactDOM.render( <App />, document.getElementById('app') );
2. As an inline function
You might not always want to declare a function and then pass the function name. For a start, you need to come up with a name for the function. It could match the prop name, like if the prop is called action
you could call it onAction
- but on the action of what?
If the function is simple and doesn't need to be reused or called from lots of different places, you could pass an anonymous inline function instead.
Let’s keep our earlier example, but instead of passing the handleClick
function, we’ll give the prop an inline function to use.
Like this:
function Parent() {
return (
<Button onClick={() => alert("The function has been called!")}>Click Me!</Button>
)
};
3. As an inline function with parameters
Do you know when inline functions are really useful? When you need to call a function with parameters.
You can't pass parameters with a function. So let's say you had a function like this:
function sayMyName(name) {
alert(`Your name is ${name}`);
};
How can I get the Button
component to work?
// ❌ Your name is [object Object]
<Button onClick={sayMyName}>Click Me!</Button>
// ❌ calls the function on render
<Button onClick={sayMyName("codemzy")}>Click Me!</Button>
// 🥴 the button component needs to know about the name prop
<Button onClick={sayMyName} name="codemzy">Click Me!</Button>
// ✅ wrap in an inline function
<Button onClick={() => sayMyName("codemzy")}>Click Me!</Button>
This is super useful if you have a list of components and each one needs to call the same function but with different parameters.
Like this:
let users = [
{ id: 1, name: "Alan" },
{ id: 2, name: "Beth" },
{ id: 3, name: "Charlie" },
{ id: 4, name: "Donna" },
{ id: 5, name: "Erica" },
{ id: 6, name: "Freddie" },
];
function sayMyName(name) {
alert(`Your name is ${name}`);
};
return (
{ names.map(name => {
return <Button key={user.id} onClick={() => sayMyName(user.name)}>{user.name}</Button>;
})}
);
In this example, we are rendering an array of objects in React. And pass the sayMyName
function as the onClick
prop (like we were before).
But since each button belongs to a different name, we are wrapping the sayMyName
function in an anonymous inline function so that we can pass the user.name
parameter.
Now each button calls the function with a different name!
What about the key
prop? Since it's a list, we are also being good React citizens (and avoiding errors!) by passing a unique key prop for each item!
<div id="app"></div>
// button function Button(props) { return ( <button className="p-3 m-1 rounded bg-gray-200" {...props} /> ); }; // app function App() { let users = [ { id: 1, name: "Alan" }, { id: 2, name: "Beth" }, { id: 3, name: "Charlie" }, { id: 4, name: "Donna" }, { id: 5, name: "Erica" }, { id: 6, name: "Freddie" }, ]; // the function function sayMyName(name) { alert(`Your name is ${name}`); }; return ( <div className="flex flex-col w-full min-h-screen items-center justify-center p-5"> { users.map(user => { return <Button key={user.id} onClick={() => sayMyName(user.name)}>{user.name}</Button>; })} </div> ); }; ReactDOM.render( <App />, document.getElementById('app') );