Skip to content

Props

So far, our FriendlyGreeting component is kinda cool, but it isn't terribly useful. Every time we render <FriendlyGreeting />, we get the exact same result. It isn't flexible at all!

Thankfully, components have a thing called props. Props are like arguments to a function: they allow us to pass data to our components, so that the components can include customizations based on the data.

When I taught React at a local coding bootcamp, props were a common stumbling block. It can take a while for the concept to “click”. If you feel discouraged for not getting it right away, please know that it's normal to feel that way, and you can always ask questions in our community Discord!

Alright, so let's suppose we want to tweak our greeting to take a person's name, so that we can greet them!

Video Summary

  • Using expression slots, we can change the content to Greetings, {name}. But where do we get the name value from?
  • React piggybacks on the HTML pattern of passing data to elements. If we wanted to add an ID to an element, we'd say <div id="some-div">. We can do the same thing with our React elements! <FriendlyGreeting name="Josh">
  • When React renders, it'll collect all of the props into a props object. So, we can access the name value by specifying {props.name} in the JSX.
  • It's much more common in the React community to use destructuring assignment.
  • Often, React feels pretty magical. We take for granted that we can apply a prop to an element and it somehow gets provided to the function. In the second half of this video, we unpack what's actually happening here. How does React take the data we write in the render() statement and apply it to the component?

In the video, we use destructuring assignment to extract props from the function parameter. If you haven't seen this syntax before, it looks pretty wild. You can learn more about it in the Object Destructuring 👀 lesson from the JavaScript Primer reference module.

Here's the sandbox from the video:

Code Playground

Open in CodeSandbox
import React from 'react';
import { createRoot } from 'react-dom/client';

function FriendlyGreeting({ name }) {
return (
<p
style={{
fontSize: '1.25rem',
textAlign: 'center',
color: 'sienna',
}}
>
Greetings, {name}!
</p>
);
}

// The video was filmed using React 17, and so
// this playground has been updated for React 18.
const root = createRoot(document.querySelector('#root'));

root.render(
<div>
<FriendlyGreeting name="Josh" />
<FriendlyGreeting name="Anita" />
<FriendlyGreeting name="Rahul" />
</div>
);

Default values

Let's suppose we're working on our FriendlyGreeting component. We want to greet the user, but there's a problem: We don't know everyone's name.

I ran into this exact problem when I was building a tool to generate newsletter issues. I didn't know the name of every subscriber. If I didn't know their name, I wanted to render a “fallback” value:

// If I know their name:
Hey Josh!
// If not:
Hey there!

We could do this in React with the || operator, like this:

function FriendlyGreeting({ name }) {
return (
<p>
Hey {name || 'there'}!
</p>
);
}

If name is provided, it'll be used. Otherwise, we'll fall back and use “there”.

This method works, but there's an even better way to do this in React. We can specify default values for each prop:

function FriendlyGreeting({ name = 'there' }) {
return (
<p>
Hey {name}
</p>
);
}

There are a couple of benefits to this approach:

  • If we have multiple props with default values, we can see all of the defaults in the same place, rather than having them sprinkled around the component
  • The default value is “locked in”. We don't have to remember to add the fallback check everywhere we reference the name prop.
  • The || operator will occasionally surprise us by using the default value even when we've supplied a value! This can happen when the supplied value is falsy 👀.

As a result, it's become a well-established convention to specify default values within the prop object.

Here's another example. We have a decorative “HorizontalRule” component, essentially a way to draw a line between sections. It has a default width of 100px, but we can override that value:

function HorizontalRule({ size = '100px' }) {
return (
<div style={{ width: size }}>
{/* Line-drawing stuff here */}
</div>
);
}
<HorizontalRule size="250px" /> // Will be "250px"
<HorizontalRule /> // Will be "100px"