Composition over Inheritance
Problem
Deep inheritance hierarchies make components fragile and hard to understand. Changes to a base class ripple through all subclasses unpredictably, and you can’t mix behaviors from multiple parents without complex multiple inheritance or awkward workarounds that create tight coupling.
Solution
Build complex components by combining simpler ones rather than extending base classes. This creates flexible, reusable pieces that can be mixed and matched without the tight coupling and fragility of inheritance hierarchies.
Example
This example demonstrates how to build a flexible Panel component by composing smaller Header and Footer components instead of using inheritance.
// Composition: Build complex UI from simple, reusable pieces
function Panel({ header, children, footer }) {
return (
<div className="panel">
{/* Compose with Header component instead of inheriting from a base class */}
<Header>{header}</Header>
{/* Main content passed as children for maximum flexibility */}
<div className="content">{children}</div>
{/* Footer component provides consistent styling and behavior */}
<Footer>{footer}</Footer>
</div>
);
}
Benefits
- Creates flexible components that can be mixed and matched easily.
- Avoids fragile inheritance hierarchies that break with changes.
- Makes component relationships explicit through composition.
- Easier to understand since behavior is assembled rather than inherited.
- Better aligns with functional programming and React’s design philosophy.
Tradeoffs
- Can lead to deeply nested component trees that are hard to follow.
- May require passing props through multiple layers initially.
- Some developers find inheritance more familiar from OOP backgrounds.
- Can result in verbose component structures for simple use cases.
- Might need more boilerplate to wire components together.