Passing props to a card

Hand a component its data as props, and draw three different shows with one card component.

ShowCard has every value typed into its markup, so it can only ever draw The Bear. Props are how you hand a component different data.

Props are the data you pass in

You pass a prop by writing it like an attribute on the tag. The component receives them as one object, and the usual name for that object is props.

import "./styles.css";
import ShowTitle from "./ShowTitle";

export default function App() {
  return (
    <div className="page">
      <ShowTitle title="The Bear" />
      <ShowTitle title="Severance" />
      <ShowTitle name="Andor" />
    </div>
  );
}

One component, three uses, two headings. The third tag passes name, but the component reads props.title. There is no title, so props.title is undefined and the heading is empty. Nothing is reported: the name has to match on both sides.

Reading props in the parameter list

Props arrive as one object, so you can unpack them where you name the parameter. That is destructuring, and it is how most React code reads props.

import "./styles.css";
import ShowTitle from "./ShowTitle";

export default function App() {
  return (
    <div className="page">
      <ShowTitle title="The Bear" year={2022} />
      <ShowTitle title="Severance" year={2022} />
    </div>
  );
}

The names inside the braces are the prop names. From here on title means props.title.

Values that are not strings need braces

Quotes make a string. Every other value — a number, an object, a variable — goes in braces.

import "./styles.css";
import YearBox from "./YearBox";

export default function App() {
  return (
    <div className="page">
      <YearBox label='year="2022"' year="2022" />
      <YearBox label="year={2022}" year={2022} />
    </div>
  );
}

Both boxes show the same year, so the screen gives nothing away. Adding 1 tells them apart: the left box got text, and text joins, so it reads 20221. The right box got a number, and numbers add, so it reads 2023. Write year={2022}.

Passing the whole show object

Five props on one tag gets long. You can pass one object instead, the same show object as in Working with Objects.

import "./styles.css";
import { ShowRow, PlainRow } from "./ShowRow";

export default function App() {
  const theBear = { title: "The Bear", year: 2022, rating: 8.6 };

  return (
    <ul className="list">
      <ShowRow show={theBear} />
      <PlainRow show={theBear} />
    </ul>
  );
}

The second row is almost empty. PlainRow was handed { show: theBear }, and that object has no title of its own, so every field is undefined. One show prop keeps the tag short, and the app moves to that shape once the shows live in a list.

Props only go down

Type a new title at the top of the tree, then switch on Let a card rename itself.

1Props go down
App
App owns the list of shows, so App is where a title can change.
ShowList
ShowList hands each show to a ShowCard. It only passes them along.
ShowCard
T
Drama
The Bear
2022·8.6
ShowCard
S
Thriller
Severance
2022·8.7
ShowCard
A
Sci-Fi
Andor
2022·8.4
Type a new title in App. It travels down to ShowList, then down to the card that title belongs to, and only then does the card change.
2Same props in, same markup out
Two calls, the same props in both
<ShowCard title="Severance" year={2022} genre="Thriller" rating={8.7} /><ShowCard title="Severance" year={2022} genre="Thriller" rating={8.7} />
Run 1 time so far
Call 1
S
Thriller
Severance
2022·8.7
Call 2
S
Thriller
Severance
2022·8.7
Same props in, same markup out, every time. Call again as often as you like: ShowCard reads the props it was given and draws the same card, so the two never drift apart.

The title travels down and the card follows, the card cannot change what it was given, and the same props always draw the same card.

Three cards from one component

ShowCard now takes the five things a card shows, so App can draw any show it likes.

import "./styles.css";
import ShowCard from "./ShowCard";

export default function App() {
  return (
    <div className="page">
      <ShowCard title="The Bear" year={2022} genre="Drama" rating={8.6} still="still-warm" />
      <ShowCard title="Severance" year={2022} genre="Thriller" rating={8.7} still="still-cold" />
      <ShowCard title="Andor" year={2022} genre="Sci-Fi" rating={8.4} still="still-dusty" />
    </div>
  );
}

One component, three sets of props, three cards. ShowCard did not change between them; only the data did.

Common mistakes

  • A prop name that does not match. The tag passes name and the component reads title, so the value is undefined and nothing is drawn.
  • A number in quotes. year="2022" passes text, which looks right on screen and behaves like text everywhere else. Use braces.
  • Writing to a prop. A component cannot change what it was given. Only the component that owns the data can change it.

Exercise

Severance has lost its title. One more thing is wrong that the screen will not show you: a number is being passed as text.

Fix both so the page reads:

Three cards side by side. The Bear, Drama, 2022 · ★ 8.6. Severance,
Thriller, 2022 · ★ 8.7. Andor, Sci-Fi, 2022 · ★ 8.4. Each card has a
title above its year.

Hint: the names on the tag have to match the names in the parameter list, and a number belongs in braces.

import "./styles.css";
import ShowCard from "./ShowCard";

export default function App() {
  return (
    <div className="page">
      <ShowCard title="The Bear" year={2022} genre="Drama" rating={8.6} still="still-warm" />
      <ShowCard name="Severance" year={2022} genre="Thriller" rating={8.7} still="still-cold" />
      <ShowCard title="Andor" year="2022" genre="Sci-Fi" rating={8.4} still="still-dusty" />
    </div>
  );
}