React patterns evolved from mixins to HOCs to render props to hooks — compound components share implicit state for flexible APIs, while custom hooks have replaced most logic-sharing patterns.
Mixins → HOCs → Render Props → Custom Hooks. Each generation improved composability and simplified logic sharing.
Functions that wrap components to inject props. Suffer from wrapper hell, prop collisions, and poor TypeScript inference — largely replaced by hooks.
Components that call a function prop to delegate rendering. Still used by headless UI libraries for behavior + rendering separation.
Plain functions that extract reusable stateful logic — compose naturally without wrapper components. The modern default.
Related components sharing implicit state via Context — the standard pattern for flexible component APIs (tabs, selects, accordions).
React has gone through several generations of component design patterns. Understanding this evolution — and when each pattern is still appropriate — demonstrates senior-level React knowledge.
Mixins (deprecated) → Higher-Order Components → Render Props → Custom Hooks. Each generation solved the same problem — sharing stateful logic between components — with increasing simplicity and composability.
A HOC is a function that takes a component and returns a new enhanced component: const EnhancedComponent = withAuth(MyComponent). The HOC wraps the original component, injecting props (auth data, theme, etc.) without modifying the component itself.
Common examples: withRouter (React Router v5), connect() (Redux), withAuth, withTheme.
Problems: wrapper hell (deeply nested component trees), prop collision (two HOCs injecting the same prop name), hard to trace which HOC provides which prop, and TypeScript type inference struggles with HOCs.
A render prop is a function prop that a component calls to determine what to render: <Mouse render={({ x, y }) => <Cursor x={x} y={y} />} />. The Mouse component handles the logic (tracking mouse position) and delegates rendering to the consumer via the function.
The children prop can also be a function: <Mouse>{({ x, y }) => <Cursor x={x} y={y} />}</Mouse>. This is the same pattern — the prop name doesn't matter.
Render props are still used by headless UI libraries (Downshift, Headless UI) where the library handles behavior and the consumer controls rendering.
Custom hooks extract reusable stateful logic into plain functions: const { x, y } = useMouse(). They solve the same problem as HOCs and render props without wrapper components, prop collisions, or composition complexity.
Hooks compose naturally — a custom hook can call other hooks, and you can use multiple hooks in one component without nesting. This is why hooks replaced most HOC and render prop usage.
Compound components are a set of related components that share implicit state and work together as a unit. The classic example is HTML's <select> and <option> — they communicate implicitly.
In React, compound components use Context to share state:
<Tabs defaultValue="a">
<TabList>
<Tab value="a">Tab A</Tab>
<Tab value="b">Tab B</Tab>
</TabList>
<TabPanels>
<TabPanel value="a">Content A</TabPanel>
<TabPanel value="b">Content B</TabPanel>
</TabPanels>
</Tabs>The parent (Tabs) manages state, and children (Tab, TabPanel) consume it via Context. This creates a flexible, declarative API where consumers control structure and layout.
Compound components are still the dominant pattern for component libraries (Radix UI, Headless UI, Reach UI) because they give consumers maximum flexibility.
Hooks replaced HOCs and render props for logic sharing because they compose without wrapper hell. Compound components remain the standard for flexible component APIs. Understanding the evolution (and why each pattern exists) demonstrates experience with real React codebases across different eras.
Fun Fact
The render props pattern was so popular that Michael Jackson (the developer, not the musician) coined the term and wrote a famous blog post in 2017 titled 'Use a Render Prop!' arguing it was superior to HOCs. Within two years, hooks made the post largely obsolete — Jackson himself acknowledged this and moved on to co-create Remix.