Suggest an editImprove this articleRefine the answer for “Composition vs inheritance in React”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Composition vs inheritance in React**: React uses composition, not class hierarchies. Components wrap other components via `children` or named props. ```tsx function Card({ title, children }: { title: string; children: React.ReactNode }) { return <div className="card"><h2>{title}</h2>{children}</div>; } // <Card title="Profile"><Avatar /></Card> ``` **Key point:** React docs recommend never subclassing your own components. Use `children`, render props, or hooks instead.Shown above the full answer for quick recall.Answer (EN)Image**Composition vs inheritance in React** - composition assembles UI from nested components via props like `children`, while inheritance extends class hierarchies through `extends`. ## Theory ### TL;DR - Inheritance is like Russian dolls: one fits inside another in a fixed order. Composition is like LEGO: snap any pieces together freely. - Main difference: composition reuses components without locking you into parent-child class chains. - React docs explicitly say: never subclass your own components beyond `React.Component`. - Decision rule: use composition in 99% of cases. Hooks replace the remaining 1% where shared logic once pushed teams toward inheritance. ### Quick example ```tsx // Inheritance (avoid): rigid and brittle class Popup extends React.Component { render() { return <div className="popup">{this.props.children}</div>; } } class Dialog extends Popup { // locked to Popup's structure // any change in Popup breaks Dialog } // Composition (preferred): flexible function Popup({ children }: { children: React.ReactNode }) { return <div className="popup">{children}</div>; } function Dialog({ title, children }: { title: string; children: React.ReactNode }) { return ( <Popup> <h2>{title}</h2> {children} </Popup> ); } ``` `Dialog` wraps `Popup` without extending it. You can swap `Popup` for anything without touching `Dialog`. ### Key difference Class inheritance creates a single prototype chain. Change the base class and everything downstream breaks. Composition passes data through props and keeps components independent. React's fiber architecture traverses the JSX tree top-down, mounting each composed child as a separate unit with its own state and lifecycle. Inheritance flattens that into one object. That is why composition works cleanly with hooks, and why the React team stopped recommending class hierarchies after hooks landed in 16.8. ### When to use - Generic wrapper around any content (modal, card, layout) - use the `children` prop. - Multiple behaviors on one component (loading state plus tooltip on a button) - compose with HOCs or hooks. - Shared state across the app (auth, theme, locale) - Context API, not inheritance. - Simple visual reuse (card, badge, layout shell) - composition, always. ### Comparison table | Aspect | Composition | Inheritance | |---|---|---| | **Flexibility** | Mix any components freely | Fixed parent-child chain | | **Reusability** | Wrap unrelated UIs | Only extends direct children | | **Maintenance** | Change wrapper independently | Base changes ripple everywhere | | **React support** | Official pattern, hooks-friendly | Discouraged past `React.Component` | | **When to use** | 99% of cases | Legacy class code only | ### Common mistakes **Mistake: subclassing your own components** ```tsx // Wrong: fragile chain class ThemedButton extends React.Component { /* theme prop */ } class PrimaryButton extends ThemedButton { /* breaks if theme changes */ } // Fix: variant prop + Context for theme function Button({ variant, children }: { variant: string; children: React.ReactNode }) { return <button className={`btn-${variant}`}>{children}</button>; } ``` The chain `ThemedButton -> PrimaryButton -> DangerButton` looks tidy until you need to change the base. Then every subclass breaks. **Mistake: expecting children to receive data automatically** ```tsx // Wrong: UserInfo gets no data <Card><UserInfo /></Card> // Fix: render props when children need parent data <Card renderUser={(user) => <UserInfo user={user} />} /> ``` Children do not inherit parent state. You pass it explicitly or pull it from Context. **Mistake: calling hooks inside class components** ```tsx // Wrong: invalid hook call class MyComponent extends React.Component { render() { const [count, setCount] = useState(0); // Error } } ``` Hooks only work inside functional components. For shared stateful logic, extract a custom hook and use it across components. ### Real-world usage - Material-UI v5: `<Modal><Form /></Modal>` wraps any content without extending `Modal`. - Next.js 14 app router: `<Layout><Page /></Layout>` is the standard layout composition pattern. - Chakra UI: compound components like `<Box>` accept any children. - React Aria: `<Dialog>` takes any content via `children`. ### Follow-up questions **Q:** Why does React have `React.Component` at all if inheritance is discouraged? **A:** `React.Component` is a thin base class for lifecycle integration. It is the one sanctioned use of inheritance in React. User-defined subclassing beyond that violates single responsibility, which is what the docs warn against. **Q:** Show how to share logic between components without inheritance. **A:** Extract a custom hook. `useModal()` returns state and handlers. Any component can call it. No `extends` needed. **Q:** When would you pick Context over composition? **A:** Composition is explicit: you pass props directly. Context fits data that many components at different tree levels need without prop drilling (theme, auth, locale). Use composition first; reach for Context when prop chains get too deep. **Q:** What replaced mixins, and why were mixins worse than inheritance? **A:** Hooks replaced mixins. Mixins patched methods directly onto a component's prototype, which caused naming collisions and made code impossible to trace. Hooks compose pure functions with no side effects on the component object. That is the senior-level answer interviewers look for. ## Examples ### Basic: card with any content ```tsx function Card({ title, children }: { title: string; children: React.ReactNode }) { return ( <div className="card"> <h3>{title}</h3> <div className="card-body">{children}</div> </div> ); } // Same Card, two completely different interiors <Card title="Profile"> <Avatar src={user.avatar} /> <UserInfo name={user.name} /> </Card> <Card title="Settings"> <SettingsForm /> </Card> ``` One `Card` component. Two completely different interiors. No `extends`. ### Intermediate: slot pattern for a page layout ```tsx // Named slots via props - used by Next.js app router layouts function Layout({ header, sidebar, content, }: { header: React.ReactNode; sidebar: React.ReactNode; content: React.ReactNode; }) { return ( <div className="layout"> <header>{header}</header> <aside>{sidebar}</aside> <main>{content}</main> </div> ); } // Each slot gets its own component <Layout header={<Navbar user={currentUser} />} sidebar={<Sidebar links={navLinks} />} content={<DashboardPage />} /> ``` `Layout` has no idea what `Navbar`, `Sidebar`, or `DashboardPage` look like. It just arranges them. I have used this pattern in every non-trivial React project and it holds up well when the design changes, because you can swap any slot without touching the others.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.