Passing props to a component
Pass props to React components and read them with destructuring, defaults, and children. See why props are read-only, and how they change over time.
- 01Pass and read propsGive a component props from its parent, read them with destructuring, set defaults for missing ones, and pass markup as
children. - 02Forward props safelyPass an object's properties with spread, forward the rest to an element, and avoid the stray attributes and overwritten values spread can cause.
- 03Treat props as read-only snapshotsExplain what React 19 does when a component writes to its props, in development and in production, and how a parent passes new props instead.
One card component, many teas
In Your first component, the menu page used TeaCard three times, and all three cards said the same thing, because the tea was typed into the component. A real menu needs each card to show its own tea. The parent, MenuPage, should say which tea each card shows, and TeaCard should only draw it. That is what props are for. The result is live:
function TeaCard({ name, price }) { return ( <article className="tea-card"> <h3>{name}</h3> <p>${price}</p> </article> );} export default function MenuPage() { return ( <main> <TeaCard name="Green tea" price={3} /> <TeaCard name="Chai" price={4} /> <TeaCard name="Iced lemon tea" price={5} /> </main> );}Look at the bottom first. Lines 13 to 15 use TeaCard three times, each with two attributes, like name="Chai" price={4} on line 14. On a component's tag, these are called props, short for "properties". They're written like the attributes in JavaScript in JSX with curly braces: a string in quotes, anything else in braces.
Now the top. Line 1 says TeaCard takes a name and a price, and lines 4 and 5 show them. The result shows three different cards from one function: Green tea $3, Chai $4, and Iced lemon tea $5. Press Edit & run and change price={4} on line 14 to price={6}: only the Chai card changes.
<TeaCard name="Chai" price={4} />. React gathers them into one object and calls TeaCard with it, the way you pass an argument to a function.A print shop has one business card design. Each customer fills in an order form with their own name and phone number, and the printer prints from the form. The printer never edits your form; if you want a different card, you hand in a new one.
- In real life: One business card design the shop keeps
- In React: The
TeaCardcomponent - In real life: The order form you fill in: name, phone number
- In React: The props on the tag:
name,price - In real life: The printer reads your form, but never writes on it
- In React: The component reads its props, but never changes them
- In real life: For a different card, you hand in a new form
- In React: For a different card, the parent passes new props
Props are the values a parent passes to a component. The parent writes them on the component's tag. React gathers them into one object and calls the component with it, like an argument to a function. The component reads its props to decide what to show, and never changes them.
Props arrive as one object
A component is a function, and it gets all its props in its first parameter, as one object. This card takes that object whole, calls it props, and prints it. Press Edit & run to see the console:
function TeaCard(props) { console.log(props); return ( <article className="tea-card"> <h3>{props.name}</h3> <p>${props.price}</p> </article> );} export default function MenuPage() { return <TeaCard name="Green tea" price={3} />;}Line 1 names the parameter props. Line 2 prints it: { name: "Green tea", price: 3 }, the two attributes from line 12 as an object. Lines 5 and 6 read each one with a dot, props.name and props.price. You'll see the log twice: in development, the StrictMode every new project has calls each component twice to catch mistakes, which the Keeping components pure lesson explains.
Where does the object come from? Remember from Writing markup with JSX that every tag becomes a jsx() call. Here is line 12, compiled:
jsx(TeaCard, { name: "Green tea", price: 3 });The first argument is your function, TeaCard, and the second is the props object, built from the attributes. When React renders this element, it calls TeaCard with that object. Props are a function's arguments, gathered into one object.
Most components don't keep the whole object. They take out the props they need with destructuring, right in the parameter list, as the menu's line 1 does: function TeaCard({ name, price }). That's short for this:
function TeaCard(props) {
const { name, price } = props;
// …the same return as before
}Line 2 makes two variables from the object's properties of the same names. A prop you don't name is simply not used. Destructuring is the usual way to read props, and the JavaScript you need for React lesson shows more of it.
Since props are function arguments, they can be any JavaScript value. The quotes or braces you write decide which. These two tags look almost the same:
function PriceTag({ price }) { return <p>With a cookie: ${price + 1}</p>;} export default function App() { return ( <> <PriceTag price={3} /> <PriceTag price="3" /> </> );}Line 8 passes the number 3, so line 2 adds 1 and shows $4. Line 9 passes the string "3", and + on a string joins text, so it shows $31. Use braces for numbers, booleans, and everything that isn't text. Objects and functions work too:
function TeaCard({ tea, onAdd }) { return ( <article className="tea-card"> <h3>{tea.name}</h3> <p>${tea.price}</p> <button onClick={onAdd}>Add to cart</button> </article> );} export default function MenuPage() { return ( <TeaCard tea={{ name: "Chai", price: 4 }} onAdd={() => console.log("Chai added")} /> );}Line 14 passes an object, with the double curlies from the last lesson: outer braces for JavaScript, inner ones for the object. Line 15 passes an arrow function, and line 6 hands it to the button's onClick. Click Add to cart: the console says Chai added. Passing functions is how a child tells its parent something happened; the Responding to events lesson goes further.
Two names are special. key, which you'll give list items, is kept by React and never reaches your component; props.key is undefined, and React warns if you read it. And since React 19, ref reaches a function component as an ordinary prop; Manipulating the DOM with refs covers it.
Default values for missing props
Most teas come in a regular size, so the parent shouldn't have to write size="Regular" every time. Destructuring can give a prop a default value, with =:
function TeaCard({ name, price, size = "Regular" }) { return ( <article className="tea-card"> <h3>{name}</h3> <p>{size}: ${price}</p> </article> );} export default function MenuPage() { return ( <main> <TeaCard name="Green tea" price={3} /> <TeaCard name="Chai" price={5} size="Large" /> <TeaCard name="Oolong" price={4} size={undefined} /> <TeaCard name="Mint tea" price={3} size={null} /> </main> );}Line 1 says: if size is missing, use "Regular". The four cards show when that happens:
- Line 13 leaves
sizeout. It'sundefined, so the default fills in:Regular: $3. - Line 14 passes
"Large", so the default isn't needed:Large: $5. - Line 15 passes
undefinedon purpose. That counts as missing:Regular: $4. - Line 16 passes
null. That's a value, so the default isn't used, and React shows nothing fornull: the card says only: $3.
How to read this table: each row is one way a parent can write the prop, and the value size gets.
| When the parent writes | size is | Why |
|---|---|---|
<TeaCard name="Green tea" price={3} /> | "Regular", the default. | The prop is missing, so size is undefined and the default fills in. |
size="Large" | "Large". | The parent passed a value, so the default isn't used. |
size={undefined} | "Regular", the default. | Passing undefined is the same as leaving the prop out. |
size={null} | null, and nothing shows. | null is a value, so the default isn't used. React shows nothing for it. |
size="" or size={0} | "" or 0. | Empty text and zero are values too. Only undefined gets the default. |
Older React code set defaults another way, with a defaultProps object on the function. The React 19 upgrade guide removed it from function components, and React 19.3.1 ignores it without a word:
function TeaCard({ name, size }) { return <p>{name}: [{size}]</p>;} TeaCard.defaultProps = { size: "Regular" }; export default function MenuPage() { return <TeaCard name="Green tea" />;}Line 5 sets the old-style default, and line 8 leaves size out. The brackets on line 2 stay empty: Green tea: []. If you meet defaultProps in older code, move each default into the destructuring. (Class components, an older way to write components, still support it.)
The children prop: markup inside a component
So far every component tag closed itself, <TeaCard />. A component can also have an opening and a closing tag, with markup between them, like a <div>. That markup reaches the component as a prop named children. This is how you build wrappers: a panel, a card frame, a dialog box.
function Panel({ title, children }) { return ( <section className="panel"> <h3>{title}</h3> {children} </section> );} export default function ShopPage() { return ( <> <Panel title="Today's special"> <p>Chai with a free cookie, $4.</p> </Panel> <Panel title="Join the tea club"> <input placeholder="Email" /> <button>Join</button> </Panel> </> );}Line 1 takes two props, title and children. Line 4 shows the title, and line 5 places {children} under it. In ShopPage, lines 13 to 15 put a paragraph between <Panel> and </Panel>, and lines 16 to 19 put a box and a button. The result shows both panels, each with its own content, inside the same frame from styles.css.
children isn't special syntax. Here are lines 13 to 15 as TypeScript's compiler writes them:
jsx(Panel, {
title: "Today's special",
children: jsx("p", { children: "Chai with a free cookie, $4." }),
});The paragraph is just another key in the props object, on line 3. You could even write children= as an attribute; nobody does, because markup between the tags is easier to read.
ShopPage writes between <Panel> and </Panel> arrives in the children prop. Panel decides where it goes by writing {children} in its own markup.What arrives in children depends on what you write between the tags. Pick one below, and React renders it on this page:
function Inspect({ children }) { return <div className="inspect">{children}</div>;} export default function App() { return <Inspect></Inspect>;}Inspectchildren is undefined
Nothing between the tags, so the component gets no children prop: it's undefined.
Nothing between the tags gives undefined, text gives a string, one tag gives one element, and two or more pieces give an array. Even Chai: {4} is two pieces, the text and the number. You rarely need to know which: place {children} in your markup, and React shows whatever it is, as the last lesson's braces do.
Passing props along with spread
Tea data often arrives as objects, and writing name={chai.name} price={chai.price} … for every property is long. JSX lets you spread an object onto a tag:
const chai = { name: "Chai", price: 4, size: "Large" }; function TeaCard({ name, price, size }) { return ( <article className="tea-card"> <h3>{name}</h3> <p>{size}: ${price}</p> </article> );} export default function MenuPage() { return <TeaCard {...chai} />;}Line 13, <TeaCard {...chai} />, passes each property of chai (line 1) as its own prop: the same as name={chai.name} price={chai.price} size={chai.size}. The card shows Large: $4.
Spread also works the other way, to pass along props you don't use. This is common for small components that wrap one HTML element:
function ShopButton({ variant = "plain", ...rest }) { return <button className={`btn ${variant}`} {...rest} />;} export default function Checkout() { return ( <> <ShopButton variant="primary" type="submit">Pay $7</ShopButton> <ShopButton disabled aria-label="Remove Chai">Remove</ShopButton> </> );}Line 1 takes variant, with a default, and collects every other prop into rest with the ... rest syntax. Line 2 uses variant for the class and spreads rest onto the real <button>. So line 8's type="submit" and line 9's disabled and aria-label reach the button. So do the words Pay $7 and Remove: they're children, and children is a prop like any other, so it travels in rest. Line 9's disabled with no value means disabled={true}; the second button is greyed out.
Spread is short to write, and that's also its risk. This card spreads everything it gets onto its element:
function TeaCard({ name, ...rest }) { return ( <article className="tea-card" {...rest}> <h3>{name}</h3> </article> );} const chai = { name: "Chai", price: 4, inStock: true, className: "sale" }; export default function MenuPage() { return <TeaCard {...chai} />;}The result looks almost right, but three things went wrong. Press Edit & run to read the console:
- Stray attributes.
priceisn't an HTML attribute, but it lands on the page asprice="4". Right-click the card and inspect it to see it. - Warnings.
inStockcan't be an attribute at all, so React warns:React does not recognize the `inStock` prop on a DOM element. - Replaced values. Props are read left to right, and a later one wins.
{...rest}comes afterclassName="tea-card"on line 3, so the data'sclassName: "sale"replaces it, and the card loses its border.
Spread is fine when you choose what goes in, as ShopButton does: it forwards button attributes to a button. Otherwise, name your props, so anyone reading the component can see what it takes. Also never spread an object that holds a key: React warns, and wants key written on the tag itself.
Props are read-only
A happy hour takes a dollar off every tea. The quickest idea is to change the price prop inside the card. Here it is, with React 19.3.1 in development, as every live example runs:
function TeaCard(props) { props.price = props.price - 1; return ( <article className="tea-card"> <h3>{props.name}</h3> <p>Happy hour: ${props.price}</p> </article> );} export default function MenuPage() { return <TeaCard name="Chai" price={4} />;}The result is an error: Cannot assign to read only property 'price' of object '#<Object>', from line 2. In development, React freezes every props object with Object.freeze, so its properties can't be changed. Your component file is a module, and modules run in strict mode, where writing to a frozen property throws instead of failing quietly. Here is where React does it, in ReactJSXElement.js, the file that builds every element:
if (Object.freeze) {
Object.freeze(element.props);
Object.freeze(element);
}These lines sit inside if (__DEV__), a block that only development builds keep. Read them at lines 276 to 279 of ReactJSXElement.js, release v19.3.1, and the block's start at line 240. Line 2 freezes the props; line 3 freezes the element that holds them.
A production build, the one your users download, leaves these lines out to save time. There, the same assignment runs without an error and the card shows Happy hour: $3. It looks fixed, but only that one render's object changed. The parent still has 4, and the next time MenuPage renders, it makes a brand-new props object with price: 4, and your change is gone. Code that only works in production is still a bug; development catches it for you.
The fix is to leave the prop alone and work out a new value from it:
function TeaCard({ name, price }) { const happyHourPrice = price - 1; return ( <article className="tea-card"> <h3>{name}</h3> <p>Happy hour: ${happyHourPrice}</p> </article> );} export default function MenuPage() { return <TeaCard name="Chai" price={4} />;}Line 2 makes happyHourPrice from price, and line 6 shows it: Happy hour: $3. The prop is untouched. (The destructured price is a plain local variable, so reassigning it wouldn't touch the props object either, but a new name says what the value means.)
The freeze is shallow: it covers the props object itself, not objects inside it. So this card, which changes a property of an object prop, gets no error at all:
const chai = { name: "Chai", price: 4 }; function TeaCard({ tea }) { tea.price = tea.price - 1; return ( <article className="tea-card"> <h3>{tea.name}</h3> <p>Happy hour: ${tea.price}</p> </article> );} export default function MenuPage() { return <TeaCard tea={chai} />;}Line 4 takes a dollar off tea.price, and tea is chai from line 1: the parent's own object, not a copy (the Objects and references lesson explains why). The result says Happy hour: $2, two dollars off, not one. StrictMode called TeaCard twice, and each call took off another dollar from the same object. That double call exists to make exactly this kind of bug show up. In production there's one call per render, so it says $3 at first, then drops a dollar every time the card renders again.
How to read this table: each row asks one question about writing to props, in development and in a production build.
| Question | In development | In a production build |
|---|---|---|
| Is the props object frozen? | Yes. React calls Object.freeze on it. | No. React skips the freeze to save time. |
What does props.price = 3 do? | It throws a TypeError, because a module's code runs in strict mode. | It changes this render's object, and nothing else. The parent still has its own value. |
What does tea.price = 3 do, when tea is a prop? | It works, because freezing is shallow. StrictMode's second call takes off another dollar, which shows the bug. | It works, and changes the parent's object, so every later render sees the changed price. |
| What should you write instead? | A new value: const happyHourPrice = price - 1;. | The same. Code that only works in production is still a bug. |
Props that change over time
Read-only doesn't mean fixed forever. A component often shows different props over time: a cart badge's count goes up with every tea. The change happens in the parent, which passes new props. Here the parent keeps the count in state, data React remembers between renders, as in Why React?:
import { useState } from "react"; function CartBadge({ count }) { return <p>Cart: <strong>{count}</strong> {count === 1 ? "item" : "items"}</p>;} export default function ShopHeader() { const [count, setCount] = useState(0); return ( <header> <CartBadge count={count} /> <button onClick={() => setCount(count + 1)}>Add a tea</button> <button onClick={() => setCount(0)}>Empty cart</button> </header> );}Line 8 keeps count in ShopHeader, starting at 0. Line 11 passes it to CartBadge, which only reads it (line 4). Click Add a tea: line 12 calls setCount(count + 1), React calls ShopHeader again, and line 11 now passes count={1}. React calls CartBadge with a new props object, and the badge says Cart: 1 item. Empty cart sets it back to 0. The State: a component's memory lesson covers useState fully.
Does the badge get the same props object with a new number in it, or a new object? Find out below: the playground keeps every props object CartBadge renders with, and reads each one again after every click.
import { useState } from "react"; function CartBadge({ count }) { return <p>Cart: <strong>{count}</strong> {count === 1 ? "item" : "items"}</p>;} export default function ShopHeader() { const [count, setCount] = useState(0); return ( <header> <CartBadge count={count} /> <button onClick={() => setCount(count + 1)}>Add a tea</button> <button onClick={() => setCount(0)}>Empty cart</button> </header> );}0 rendersCart: 0 items
CartBadge has rendered once, with one props object. Press Add a tea.
Each render brings a new object, and the old ones still say exactly what they said: { count: 0 } stays 0. React never changes props. It renders the parent again, which makes new elements with new props, and the old objects are dropped. So props are a snapshot: the parent's data at the moment of one render.
ShopHeader render again, and React hands CartBadge a new props object. The old objects aren't changed; React stops using them, and they're dropped.A tea menu wired with props
Here is everything at once, in three files like a real project: App.jsx, Panel.jsx, and TeaCard.jsx, in tabs. Click Add to cart on two teas:
import { useState } from "react";import Panel from "./Panel.jsx";import TeaCard from "./TeaCard.jsx"; export default function MenuPage() { const [cart, setCart] = useState([]); const add = (name) => setCart([...cart, name]); return ( <main> <Panel title={`Your cart (${cart.length})`}> <p>{cart.length === 0 ? "Nothing yet." : cart.join(", ")}</p> </Panel> <Panel title="Today's teas"> <TeaCard name="Green tea" price={3} onAdd={add} /> <TeaCard name="Chai" price={4} size="Large" onAdd={add} /> <TeaCard name="Iced lemon tea" price={5} soldOut onAdd={add} /> </Panel> </main> );}- Line 6 keeps the cart in state, and line 7 makes
add, a function that puts a name in a new cart array. - Lines 11 to 13: the first
Panel's title comes from a template literal,Your cart (2)after two clicks, and itschildrenis a paragraph listing the cart. - Lines 15 to 17: three
TeaCards. Line 15 uses the size default, line 16 passessize="Large", and line 17 writessoldOutwith no value, which passestrue. Each getsaddasonAdd. - In the
TeaCard.jsxtab, line 1 sets two defaults, and line 6 callsonAdd(name)on a click, so the card tells the parent which tea, and the parent changes the cart.
Data flows down as props: from MenuPage into each Panel and TeaCard. Changes go up as calls to functions the parent passed down, and come back down as new props.
const total = price * 2;props.price = 5;const label = size ?? "Regular";tea.price = tea.price - 1;const sorted = items.toSorted();items.push("Cake");const { price, ...others } = props;items.sort();
Each line sits inside a component whose props are price, size, tea (an object), and items (an array). Sort it: does it only read props, or change them?
Common mix-ups
- "Props are strings, like HTML attributes." No. Quotes pass a string, but braces pass any value: numbers, objects, arrays, functions.
price="3"andprice={3}are different props. - "A component can change its props to update the screen." No. Props are read-only. The parent changes its own data, usually state, and passes new props.
- "A default is used whenever a prop is empty." No. Only when it's missing or
undefined.null,"", and0are kept. - "
defaultPropssets defaults." Not on function components in React 19: it's ignored. Use a default in the destructuring. - "
childrenis special syntax." No. It's an ordinary prop that holds what's between the tags, and it only shows where the component writes{children}. - "Spreading props is always safe." No. Unknown props become attributes or warnings, and a later prop replaces an earlier one with the same name.
- "No error means it's fine to change props." No. Production builds don't freeze props, and objects inside props are never frozen. The bug is still there.
Practice exercises
Each exercise shows its result under the code, or when you press Edit & run. Change the code, and the result updates as you type. Try it yourself first, then use the hints.
What does the card's paragraph show? Answer first, then press Edit & run to check.
function TeaCard({ name, price, size = "Regular" }) {
return (
<article className="tea-card">
<h3>{name}</h3>
<p>{size}: ${price}</p>
</article>
);
}
const tea = { name: "Oolong", price: 4 };
export default function MenuPage() {
return <TeaCard name={tea.name} price={tea.price} size={tea.size} />;
}function TeaCard({ name, price, size = "Regular" }) { return ( <article className="tea-card"> <h3>{name}</h3> <p>{size}: ${price}</p> </article> );} const tea = { name: "Oolong", price: 4 }; export default function MenuPage() { return <TeaCard name={tea.name} price={tea.price} size={tea.size} />;}tea.size is undefined, because tea has no such property. Passing size={undefined} counts as missing, so the default "Regular" fills in, and the paragraph says Regular: $4.
All three cards say Green tea. Make the cards show Green tea $3, Chai $4, and Mint tea $2, with props.
function TeaCard() { return ( <article className="tea-card"> <h3>Green tea</h3> <p>$3</p> </article> );} export default function MenuPage() { return ( <main> <TeaCard /> <TeaCard /> <TeaCard /> </main> );}function TeaCard({ name, price }) { return ( <article className="tea-card"> <h3>{name}</h3> <p>${price}</p> </article> );} export default function MenuPage() { return ( <main> <TeaCard name="Green tea" price={3} /> <TeaCard name="Chai" price={4} /> <TeaCard name="Mint tea" price={2} /> </main> );}TeaCard now reads name and price instead of typing a tea in, and each tag passes its own. The second card says Chai and $4.
The tea guide's cards show only their titles. Make each card show the paragraph written between its tags.
function Card({ title }) { return ( <section className="panel"> <h3>{title}</h3> </section> );} export default function TeaGuide() { return ( <> <Card title="Green tea"> <p>Steep for 3 minutes.</p> </Card> <Card title="Black tea"> <p>Steep for 5 minutes.</p> </Card> </> );}function Card({ title, children }) { return ( <section className="panel"> <h3>{title}</h3> {children} </section> );} export default function TeaGuide() { return ( <> <Card title="Green tea"> <p>Steep for 3 minutes.</p> </Card> <Card title="Black tea"> <p>Steep for 5 minutes.</p> </Card> </> );}The paragraphs were always passed as children, but Card never placed them. With {children} under the heading, each card shows its own steeping time.
Happy hour takes $1 off, so the $4 tea should cost $3, but the line says $2. Fix it without changing order.
const order = { tea: "Green tea", price: 4 }; function OrderLine({ order }) { order.price = order.price - 1; return <p>{order.tea}, happy hour: ${order.price}</p>;} export default function Receipt() { return <OrderLine order={order} />;}const order = { tea: "Green tea", price: 4 }; function OrderLine({ order }) { const happyHourPrice = order.price - 1; return <p>{order.tea}, happy hour: ${happyHourPrice}</p>;} export default function Receipt() { return <OrderLine order={order} />;}The starter changed the parent's order object, twice in development, so the price said $2. Working out happyHourPrice leaves order alone: the line says $3, however many times React calls the component.
The Pay button should submit the form, and Remove Chai should be disabled, but ShopButton drops both props. Make it forward every prop except label to its button.
function ShopButton({ label }) { return <button className="btn">{label}</button>;} export default function Checkout() { return ( <form> <ShopButton label="Pay $7" type="submit" /> <ShopButton label="Remove Chai" disabled /> </form> );}function ShopButton({ label, ...rest }) { return ( <button className="btn" {...rest}> {label} </button> );} export default function Checkout() { return ( <form> <ShopButton label="Pay $7" type="submit" /> <ShopButton label="Remove Chai" disabled /> </form> );}...rest collects every prop except label, and spreading it onto the button passes type="submit" to the first one and disabled to the second. className comes before the spread, so a caller could still replace it; put it after if it must always win.
Clicking Add a tea does nothing. Make it work, keeping the count in ShopHeader. What does the cart say after two clicks?
import { useState } from "react"; function CartBadge({ count }) { return ( <p> Cart: <strong>{count}</strong>{" "} <button onClick={() => { count = count + 1; }}>Add a tea</button> </p> );} export default function ShopHeader() { const [count, setCount] = useState(0); return <CartBadge count={count} />;}import { useState } from "react"; function CartBadge({ count, onAdd }) { return ( <p> Cart: <strong>{count}</strong>{" "} <button onClick={onAdd}>Add a tea</button> </p> );} export default function ShopHeader() { const [count, setCount] = useState(0); return <CartBadge count={count} onAdd={() => setCount(count + 1)} />;}The count lives in the parent, so only the parent can change it. CartBadge calls onAdd, the parent sets its state, renders again, and passes the new count down. After two clicks the badge says Cart: 2.
Check your understanding
For each code question, write down the props object each component gets first, with each value's type. Press Edit & run on a question's code to check your answer.
Question 1 of 7What does this price tag show?
Read the code, then predictfunction PriceTag({ price }) { return <p>Two cups: ${price * 2}, with a cookie: ${price + 1}</p>; } export default function App() { return <PriceTag price="4" />; }Choose an answer to see the explanation.
Question 2 of 7What does this badge show between the brackets?
Read the code, then predictfunction Badge({ label = "New" }) { return <p>[{label}]</p>; } export default function App() { return <Badge label={null} />; }Choose an answer to see the explanation.
Question 3 of 7What does this page show from the Panel?
Read the code, then predictfunction Panel({ title }) { return <section><h3>{title}</h3></section>; } export default function App() { return ( <Panel title="Today's special"> <p>Chai, $4</p> </Panel> ); }Choose an answer to see the explanation.
Question 4 of 7In development, what happens when a component runs
props.price = 5?Choose an answer to see the explanation.
Question 5 of 7And in a production build, what does the same
props.price = 5do?Choose an answer to see the explanation.
Question 6 of 7What type does this Save button get?
Read the code, then predictfunction SaveButton(props) { return <button type="button" {...props}>Save</button>; } export default function App() { return <SaveButton type="submit" />; }Choose an answer to see the explanation.
Question 7 of 7ShopHeader re-renders with its count at 2. What does CartBadge get?
Choose an answer to see the explanation.
Key takeaways
- Props are how a parent passes data to a component. React gathers a tag's props into one object and calls the component with it.
- Read props with destructuring,
function TeaCard({ name, price }), and give missing ones defaults with=. Defaults apply to missing andundefinedprops, notnull. - Markup between a component's tags arrives as the
childrenprop, and shows where the component places it. - Spread passes an object's properties as props, and rest forwards the ones you don't use. Choose what you spread: extra props land on elements, and later props win.
- Props are read-only. React freezes them in development, so writing to one throws; production skips the freeze, but the write is still a bug. New data comes as new props from the parent, every render.
Remember the one-liner.
Props flow down as a read-only snapshot; to change them, the parent passes new ones.
Coming next: Conditional rendering. It uses props to decide what a component shows, with if, the ternary operator, &&, and null.