Props
How data flows from a parent component into a child, and why it only flows that way.
Passing data in
Props are the arguments of a component. You write them like HTML attributes, and React collects them into a single object passed as the first parameter.
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
function App() {
return <Greeting name="Ada" />;
}Values other than strings go in braces:
<Product name="Keyboard" price={49.99} inStock={true} tags={["input", "usb"]} />A prop with no value is shorthand for true, so inStock and inStock={true} mean the same thing.
Destructuring in the signature
Reading props.something repeatedly gets noisy. Most code destructures the props object directly in the parameter list.
function Product({ name, price, inStock }) {
return (
<div>
<h3>{name}</h3>
<p>{price}</p>
{inStock ? <span>In stock</span> : <span>Sold out</span>}
</div>
);
}Default values
function Button({ label = "Save changes", kind = "primary" }) {
return <button className={kind}>{label}</button>;
}The default applies when the prop is missing or explicitly undefined. Passing null does not trigger it.
The children prop
Whatever you put between a component's opening and closing tags arrives as a prop named children. This is how wrapper components are built.
function Panel({ title, children }) {
return (
<section className="panel">
<h2>{title}</h2>
<div className="panel-body">{children}</div>
</section>
);
}
function App() {
return (
<Panel title="Notes">
<p>Anything can go here.</p>
<button>Add note</button>
</Panel>
);
}Props are read-only
A component must never change its own props. They belong to the parent.
function Total({ amount }) {
amount = amount * 1.2; // Wrong: mutating a prop
return <p>{amount}</p>;
}
function Total({ amount }) {
const withVat = amount * 1.2; // Right: derive a new value
return <p>{withVat}</p>;
}The same applies to objects and arrays passed as props. Copy them before changing them rather than editing in place.
Data flows down
React's data flow is one-directional: a parent passes props to a child, never the reverse. If a child needs to affect the parent, the parent passes down a function for the child to call.
function SearchBox({ onSearch }) {
return <button onClick={() => onSearch("react")}>Search</button>;
}
function App() {
function handleSearch(term) {
console.log("Searching for", term);
}
return <SearchBox onSearch={handleSearch} />;
}The child does not know what happens next, and does not need to. That separation is what makes components reusable in a second place.
Spreading props
Spread syntax forwards a whole object of props at once. It is convenient for wrapper components and easy to overuse.
const settings = { name: "Keyboard", price: 49.99 };
<Product {...settings} />Spreading everything makes it hard to see what a component actually receives. Prefer naming props explicitly unless you are deliberately forwarding an unknown set.