Props
What are props?
Whatever you pass into a component when you use it. React bundles all of it into a single object and hands that object to the function.
propsis just a parameter name, not a keyword. You could call itdata,movieData, anything.propsis convention, not a requirement.
function MovieCard(props) {
// ...
}Calling a component passes an object
<MovieCard title="Dune" genre="Sci-Fi" rating={5} /> is basically calling MovieCard with one argument, an object built from the attributes you wrote.
<MovieCard title="Dune" genre="Sci-Fi" rating={5} />
// roughly equivalent to:
MovieCard({
title: "Dune",
genre: "Sci-Fi",
rating: 5
})Reading props
Two ways to get at them, same underlying object either way.
props.titlereads a single value straight off the object.- Destructuring,
{ title, genre, rating }, pulls several out at once. It's the same as writingconst title = props.titlefor each one, just more compact.
function MovieCard(props) {
return <h2>{props.title}</h2>
}
function MovieCard({ title, genre, rating }) {
return <h2>{title}</h2>
}Props can hold any JS value
Curly braces mean "evaluate this as JavaScript", not "insert this text". That's the whole difference between rating={5} (the number 5) and rating="5" (the string "5").
<MovieCard title="Dune" /> // string
<MovieCard rating={5} /> // number
<MovieCard watched={true} /> // boolean
<MovieCard genres={["Sci-Fi"]} /> // array
<MovieCard movie={movie} /> // object
<MovieCard onDelete={deleteMovie} /> // functionThere aren't really separate mechanisms here for "passing a value" versus "passing an expression". There's one mechanism, you pass named props to a component, and the value just happens to be able to be any JavaScript expression.
Passing a whole object as one prop
Instead of spreading a movie's fields across separate props, pass the whole object as a single prop.
const movie = {
title: "Dune",
genre: "Sci-Fi",
rating: 5
}
<MovieCard movie={movie} />- The props object becomes
{ movie: { title: "Dune", genre: "Sci-Fi", rating: 5 } }, one key,movie, whose value happens to be another object. - Receive it the same way as any other prop, destructure
{ movie }, then readmovie.title,movie.genre,movie.ratingoff it.
function MovieCard({ movie }) {
return <h2>{movie.title}</h2>
}movie={movie}is really just saying: the value of this one prop is an entire object.
No fixed shape
Props are just a plain object. Nothing enforces a contract on what's supposed to be in it.
- Don't pass a prop the component reads → it's just
undefined, same as reading any missing key off a JS object. - Pass extra props the component never reads → nothing breaks, they're simply ignored.
<MovieCard title="Dune" />
// props.rating is undefined
<MovieCard title="Dune" rating={5} director="Villeneuve" />
// director is passed along fine even though MovieCard never reads itData down, events up
Props only flow one direction: parent to child. A child that needs to affect the parent doesn't reach up directly, it calls a function the parent handed it as a prop.
// parent
<MovieCard onDelete={deleteMovie} />
// child
function MovieCard({ onDelete }) {
return <button onClick={onDelete}>Delete</button>
}The full cycle, parent owns the state, everything else follows from that:
- Parent owns the state.
- Parent passes data down to the child, as props.
- Child displays it, user interacts with it.
- Child calls the callback prop it was given.
- Parent updates its state.
- Parent passes the new data down.
- Child re-renders.
The one mental model to remember
<MovieCard title="Dune" rating={5} /> becomes the object { title: "Dune", rating: 5 }, and that object is exactly what MovieCard(props) receives. Read it as props.title, or destructure it, same data either way. Props are just data and functions, handed down from parent to child.