Passing props to a component
Make one component show different data by passing it props, the way you pass arguments to a function.
At the end of Day 1 you built a BookCard that always shows the same title and author. That is fine for one book, but a reading list has many books. You don't want to copy the component five times and change the text by hand.
What you want is one BookCard that can show any book. The parent decides which book, and the card decides how it looks. Props make that split possible.
From hard-coded to reusable
Here is the idea in action. App renders BookCard three times, each time with different information written as attributes:
Props (short for "properties") are the information a parent passes to a child component. You write them like HTML attributes: title="Dune". React collects all of them into one object and hands that object to your component function as its first argument.
So when React renders <BookCard title="Dune" author="Frank Herbert" />, it calls your function roughly like this:
BookCard({ title: 'Dune', author: 'Frank Herbert' });Try it: change one of the titles in App.js, or add a fourth BookCard with your favorite book.
Reading props inside the component
Your component receives a single object. You can read it in two ways. Both work the same.
export function BookCard(props) {
return <h2>{props.title}</h2>;
}export function BookCard({ title, author }) {
return <h2>{title}</h2>;
}The second version uses destructuring, which you met on Day 1. The curly braces in the parameter list pull title and author out of the props object and turn them into local variables. Most React code uses this style because you can see at a glance which props a component expects.
Open the console below to see the object React passes in. You may see each log twice. That is normal in development, and you'll learn why in Keeping components pure.
Default values
Sometimes a prop is optional. You can give it a fallback right in the destructuring, with =:
The first Rating doesn't pass max, so it uses 5. A default only kicks in when the prop is missing or is undefined. If a parent passes max={null} or max={0}, the default is not used.
Passing different kinds of values
So far most props have been strings. Props can hold any JavaScript value, and the syntax tells React which kind you mean:
| You want to pass | Write it like this |
|---|---|
| A string | title="Dune" |
| A number | rating={4} |
| A boolean | isFavorite={true}, or isFavorite on its own |
| A variable | author={authorName} |
| An object | book={book} or book={{ title: 'Dune' }} |
| An array | tags={['sci-fi', 'classic']} |
The rule from Day 1 still applies: quotes mean "this is literal text", and curly braces mean "this is a JavaScript expression". So rating="4" passes the string "4", while rating={4} passes the number 4.
The object row has two sets of braces. The outer pair says "here comes JavaScript", and the inner pair is the object itself. You'll see this "double curly" shape again when you style things later today.
Passing a whole object
Real data usually comes as objects. Instead of pulling every field apart in the parent, you can pass the whole object as a single prop. That is what the Reading List will do from now on:
Now if a book gains a new field, such as a rating, you only change BookCard. Every place that renders <BookCard book={...} /> keeps working.
Deep diveForwarding props with the spread syntax
Sometimes a component only passes its props straight through to a child. You can forward all of them at once with the spread syntax:
function FancyCard(props) {
return (
<div className="fancy">
<BookCard {...props} />
</div>
);
}{...props} means "pass every prop I received". It is handy, but use it with care. When everything is forwarded, it becomes harder to tell which props a component actually uses. Writing the props out by name is usually clearer.
Render three books from data
The data for three books is already in App.js, but BookCard still shows hard-coded text. Change BookCard so it takes a book prop, then render one card for each of the three book objects.
Show solution
BookCard destructures book from its props and reads fields from it. App passes a different object each time.
Writing <BookCard> three times by hand still feels repetitive. In Rendering lists you'll replace that with a single map call.
A component is written as function Card(title) and used as <Card title='Dune' />. What is inside the title variable?
Props are read-only
A component should never change its own props. Think of them as a snapshot the parent handed over for this render. If BookCard did book.title = 'Oops', it would be reaching into data that belongs to someone else, and other parts of the app that use the same object would see the change by surprise.
function BookCard({ book }) {
book.title = book.title.toUpperCase(); // Wrong: changes the parent's data
return <h2>{book.title}</h2>;
}
function BookCard({ book }) {
const shoutedTitle = book.title.toUpperCase(); // Right: make a new value
return <h2>{shoutedTitle}</h2>;
}So how does anything on screen ever change? The parent passes new props. When the parent re-renders with different data, React calls your component again with the new props object. To make data change in response to clicks and typing, you'll use state, which arrives on Day 3.
Which prop passes the number 5, not the text 5?
Day 2 progress