Chapter 2 of 4

Passing Props

How data flows from parent to child, and why props cannot be changed by the child.

Props are the inputs to a component. A parent passes them as JSX attributes; the child receives them as a single object argument.

function Badge(props) {
  return <span className={props.tone}>{props.label}</span>;
}

<Badge label="New" tone="success" />

Destructuring in the parameter list

Almost all React code destructures props in the function signature. It documents what a component needs at a glance.

function Badge({ label, tone }) {
  return <span className={tone}>{label}</span>;
}

Default values

Give a prop a default in the destructuring pattern. The default applies when the prop is missing or explicitly undefined.

function Badge({ label, tone = "neutral", isRounded = true }) {
  return (
    <span className={isRounded ? tone + " rounded" : tone}>{label}</span>
  );
}

<Badge label="Draft" />  {/* tone is "neutral" */}

Props are read only

A component must never modify the props it receives. React relies on components being predictable: the same props should always produce the same output. Mutating props breaks that guarantee and the bug usually shows up somewhere else entirely.

function Total({ order }) {
  order.total = order.total * 1.2;  // never do this
  return <p>{order.total}</p>;
}

function Total({ order }) {
  const withTax = order.total * 1.2;  // derive a new value instead
  return <p>{withTax}</p>;
}
The child asks; the parent decides.
function Parent() {
  const [count, setCount] = useState(0);
  return <Child count={count} onIncrement={() => setCount(count + 1)} />;
}

function Child({ count, onIncrement }) {
  return <button onClick={onIncrement}>Clicked {count} times</button>;
}