A senior React developer can write any component. An architect knows which pattern to reach for, when, and (crucially) when not to. Picking the wrong abstraction is one of the most expensive mistakes in a frontend codebase — it locks in shapes that end up everywhere, and untangling them costs months.
So I took a real production SaaS dashboard and consolidated it on the right patterns, measuring the impact. This is the condensed version; the full guide (all six patterns with before/after code, the composition diagram, the decision flow, and anti-patterns) is on my site 👇
Full guide: https://prepstack.co.in/blog/react-design-patterns-container-hooks-compound-render-props-hoc-provider-guide
The result (same app, before + after)
Moving from "HOC + render-props everywhere" → "Hooks + Compound + Provider":
| Metric | Before | After | Δ |
|---|---|---|---|
| Component code lines | 28,400 | 20,500 | −28% |
| Avg component reuse | 2.1× | 5.8× | +176% |
| HOCs in codebase | 14 | 2 | −86% |
| Render-prop components | 22 | 4 | −82% |
| Custom hooks | 8 | 47 | + |
| Prop-drilling bugs/qtr | 11 | 4 | −63% |
| Storybook without mocks | 38% | 84% | +121% |
| New-dev first feature | 9 days | 5 days | −44% |
| DevTools tree depth | 18 | 9 | −50% |
The 6 patterns, in one line each
1. Custom Hooks — the most important pattern. They replaced most of what HOCs and render props did. The rule: if you can name the behavior as a noun ("the searchable list", "the form draft"), it's a hook. Master these first.
2. Compound Components — HTML-shaped, composable APIs. <Tabs><Tab/></Tabs> sharing state via context. The whole Radix/shadcn design language is built on this. Best for design-system components.
3. Provider Pattern — app-scope concerns. Theme, auth, locale, feature flags. Still essential — but not a poor man's state manager (Context re-renders every consumer; use Zustand for high-frequency state).
4. Container/Presentation — now Server + Client Components. The principle (data vs view) survived; the syntax modernized. Server Component = container, 'use client' = presentation. Splitting them took Storybook-without-mocks 38% → 84%.
5. Render Props — mostly obsolete. Hooks beat it on nesting, composition, and TS. Survives only for true inversion-of-control (virtualizers, <Form>{form => ...}</Form>).
6. HOC — the demoted one. Wrapper-hell, prop collisions, messy types. If a new HOC appears in a 2026 PR, ask "could this be a hook?" — almost always yes. Survives only for legacy class components and library boundaries.
Where the wins came from
Custom hooks replacing HOC + RP duplication ~38%
Server/Client (modern container/presentation) ~22%
Compound components in the design system ~16%
Providers replacing prop-drilling ~12%
Test-without-mocks (presentational components) ~8%
Smaller DevTools tree (HOC removal) ~4%
The mental model
Patterns aren't a checklist to use — they're a vocabulary for shapes of problems. Know which shape you're looking at, reach for the matching pattern deliberately (before someone reinvents it badly in a PR), and the team stops re-solving the same thing six ways. A team with a coherent pattern vocabulary moves 2× faster than one without.
Three habits that make it work: (1) write the vocabulary down (a patterns.md), (2) prefer hooks until forced otherwise, (3) compose patterns — a real app uses all six where each fits, and can be fully coherent without ever writing a new HOC.
The full guide has all six patterns with before/after code, the composition diagram, the full metrics table, the decision flow, and the anti-patterns table:
Originally published on PrepStack.
Top comments (0)