Composition Versus Inheritance

React 7,897 has run at Meta across thousands of components without a single component inheritance hierarchy, and the official guidance has never wavered: reuse code by composing components, not by extending them. Even in the class era, extends React.Component was plumbing, not a base class to build a family tree on.

The reason is not dogma. Inheritance forces a parent to anticipate every variation a child might want and to encode each as a prop it must know about. Composition lets the parent stay ignorant: it declares a hole, and the caller fills it with anything React can render.

A rigid component beside a composed oneJavaScript
function RigidCard({ title, body, footerText }) {     // every hole must be a string
  return <div className="c"><h4>{title}</h4><p>{body}</p><small>{footerText}</small></div>;
}
function Card({ title, children, footer }) {          // holes accept any node
  return <div className="c"><h4>{title}</h4>{children}<p>{footer}</p></div>;
}
const App = () => (
  <div className="row">
    <RigidCard title="Rigid" body="Strings only." footerText="A button cannot go here." />
    <Card title="Composed" footer={<Counter />}>
      <p>Any markup fits, <b>including state</b>.</p>
    </Card>
  </div>
);

RigidCard needs a new prop, and a new branch inside it, for every kind of footer anyone ever wants. Card needed nothing: Counter is a stateful component the card has never heard of, and clicking its button re-renders the counter without touching the card. If a component needs non-visual behavior from another, export it as a plain module and import it from both; if you want a shared base class holding lifecycle logic, that is what custom Hooks (Custom Hooks) are for.