Every prop you've used since Chapter 8 follows the same direction: parent components own data (in state or as constants) and pass it down to children as props. A child can read what it receives, but can never directly reach back up and change its parent's data โ that requires callback functions, covered next in Chapter 17.
function ProductCard({ product, onAddToCart }) {
return (
<div>
<h3>{product.name}</h3>
<p>โน{product.price}</p>
<button onClick={() => onAddToCart(product.id)}>Add to Cart</button>
</div>
);
}
function App() {
const product = { id: 1, name: "Headphones", price: 1999 };
function handleAddToCart(id) {
console.log("Added:", id);
}
return <ProductCard product={product} onAddToCart={handleAddToCart} />;
}This example passes an object (product) and a function (onAddToCart) down together โ a very common real-world pattern where the parent owns the data and the logic, while the child just displays it and reports back what happened.
function Layout({ header, children }) {
return (
<div>
<div className="header">{header}</div>
<div className="body">{children}</div>
</div>
);
}
<Layout header={<h1>Dashboard</h1>}>
<p>Main content goes here.</p>
</Layout>Because JSX is just JavaScript, it can be passed as a prop value like anything else โ this pattern, combined with children, is the foundation of building flexible, reusable layout and modal components (revisited in Chapter 28).
Two sibling components (both children of the same parent) can't pass props directly to each other โ props only flow downward from a parent. To share data between siblings, that data needs to live in their shared parent's state, which is exactly the topic of Chapter 18: Lifting State Up.
Build a Parent component holding an array of book objects, passing each one down to a Book child component along with an onSelect callback function.
function Book({ book, onSelect }) {
return (
<div onClick={() => onSelect(book.title)}>
<h4>{book.title}</h4>
<p>{book.author}</p>
</div>
);
}
function Library() {
const books = [
{ title: "1984", author: "George Orwell" },
{ title: "Dune", author: "Frank Herbert" }
];
function handleSelect(title) {
console.log("Selected:", title);
}
return (
<>
{books.map((b, i) => <Book key={i} book={b} onSelect={handleSelect} />)}
</>
);
}
Q Can a child component modify the object it receives as a prop?
It shouldn't โ even though objects are passed by reference in JavaScript, mutating a prop object directly breaks React's expectations and can cause subtle bugs. Treat all received props as read-only, exactly like primitive props.
Q What's the difference between children and a regular named prop?
children is a special, implicitly-passed prop containing whatever JSX was nested between a component's opening and closing tags, while named props (like header in the example) are explicitly passed as attributes.