Composition and children
The reading list now needs a few boxes that all look alike — a border, some padding, a title bar — but hold completely different things. You could write BookBox, SearchBox and StatsBox. Or you could write the box once and let each parent decide what goes inside.
The rule
Build big from small; leave a slot, and let the parent fill it.
Build big from small. Components are combined by nesting them, not by inheriting from each other. React has no need for "a FancyCard that extends Card"; you put a Card inside something else instead.
Leave a slot. Whatever a parent writes between a component's opening and closing tags arrives as a special prop called children:
function Panel({ title, children }) {
return (
<section className="panel">
<h2 className="panel-title">{title}</h2>
<div className="panel-body">{children}</div>
</section>
);
}Let the parent fill it:
export default function App() {
return (
<main>
<Panel title="My books">
<BookCard title="Dune" author="Frank Herbert" pages={412} />
</Panel>
<Panel title="Stats">
<p>2 books, 722 pages</p>
</Panel>
</main>
);
}Panel has no idea what it contains, and that is exactly why it is reusable. You can leave more than one slot, too: any prop can hold JSX, as in <Layout sidebar={<Filters />} main={<BookList />} />.
A pleasant side effect: because App places BookCard directly inside the panel, it passes the book's data straight to BookCard. Panel never has to receive and forward props it does not care about.
The shortcut
When two components differ only in what is inside them, ask: "Is the outside the same?" If yes, make one wrapper and pass the inside as children.
Compare the outsides
BookBox,SearchBoxandStatsBoxall render the same border, padding and title bar.
You have already used this idea without noticing: an HTML <ul> does not care which <li> elements you put in it. Panel behaves the same way, and children can be anything renderable — text, a single element, several elements, or nothing at all.
The trap is forgetting to render {children}. The parent's content is passed in, but if Panel never places it in its JSX, it silently vanishes.
Drills
Answer fast — trust the rule.
In <Panel title="Stats"><p>2 books</p></Panel>, how does Panel receive the paragraph?
Panel returns <section className="panel"><h2>{title}</h2></section>. What happens to the content passed between its tags?
Which is the React way to make a special card that shares a plain card's frame?
A layout needs two separate slots, a sidebar and a main area. What works?
Remember
- Build big from small; leave a slot and let the parent fill it.
- Same outside, different inside? One wrapper with
children. - Trap: a wrapper that forgets to render
{children}swallows its content.
