Key Principle
Pattern selection must be driven by measurable performance impact and practical need, not theoretical elegance. Patterns are time-tested templates, not silver bullets. Every choice exists on a spectrum with hybrid middle-ground solutions; treat decisions as tradeoffs, not binaries.
Why This Matters
Wrong pattern choices cascade: a design pattern decision (e.g., Provider vs. prop drilling) affects hydration cost, which affects rendering strategy viability, which determines performance ceiling. These three layers -- design, rendering, performance -- are interconnected, and a heuristic at any layer saves compounding mistakes downstream.
Good Examples
Design Patterns
- Replace HOCs and render props with custom Hooks for flatter component trees and co-located logic (Ch. 14)
- Use Object.freeze + ES modules instead of Singleton classes for global state without testing fragility (Ch. 4)
- Use Provider Pattern (Context API) to eliminate prop drilling; extract custom context hooks with validation (Ch. 6)
- Compound Pattern via Context for multi-part components with shared state (Ch. 18)
Rendering
- CSR-to-SSR is a spectrum: CSR for TTI-tolerant apps, SSR for SEO/FCP, SSG/iSSG for content sites, Islands for mostly-static with interactive pockets (Ch. 20-31)
- Progressive and Selective Hydration close the "uncanny valley" between FCP and TTI (Ch. 26, 29)
- Islands Architecture achieved 83% JS reduction vs. Next.js/Nuxt.js in benchmarks (Ch. 31)
Performance
- Route-based splitting first, then component-level splitting by visibility/interaction (Ch. 37-38)
- List virtualization for 1000+ items: react-window yields ~100x speedup for 10K rows (Ch. 43)
- Preconnect over preload for cross-origin resources: 16.61% LCP improvement in case study (Ch. 30)
Counterpoints
- Not all "optimizations" improve performance: native lazy loading and react-scroll caused regressions in the case study (Ch. 30)
- Proxy Pattern incurs measurable performance overhead; avoid in hot paths (Ch. 5)
- Provider Pattern causes re-renders for all consumers on frequently-changing values; split contexts by update frequency (Ch. 6)
- HTTP/2 server push is not HTTP cache aware; service workers are the workaround, but the long-term solution remains unclear (Ch. 39)
- Ideal code-splitting granularity is not well-defined; too fine creates request overhead, too coarse defeats the purpose (Ch. 38)
Key Quotes
- "Traditional software design patterns must be re-evaluated for the modern JavaScript and React ecosystem, where many classical OOP patterns are either obsolete, replaced by language features (ES modules, Hooks), or need adaptation to component-based architectures." (EXTRACTION_SUMMARY.md, Core Thesis)
- "The book treats performance not as an afterthought but as a first-class architectural concern, connecting design decisions directly to measurable metrics (FCP, LCP, TTI, TBT, CLS)." (running-context.md, Recurring Themes)
- "Patterns are time-tested templates but not silver bullets; measure before adopting." (book-spine.md, Ch. 44 Conclusions)
- "Intuition about performance is unreliable and some 'optimizations' actually cause regressions." (running-context.md, Recurring Themes)
Rules of Thumb
Pattern Selection
- If a class-based pattern (Singleton, Mixin, Container/Presentational) has a Hook or ES module equivalent, prefer the modern alternative.
- Use the Compound Pattern when a component has 3+ tightly coupled sub-parts sharing state; otherwise plain props suffice.
- Observer Pattern trades debugging opacity for loose coupling -- use RxJS in production, not hand-rolled implementations.
- Flyweight, Factory, and Command patterns have diminishing relevance in modern JS; reach for them only when the classical use case is exact.
Rendering Strategy
- Choose by content type: static content -> SSG/iSSG; dynamic personalized content -> SSR; app-like interaction -> CSR; mostly static with interactive pockets -> Islands.
- Use iSSG (stale-while-revalidate + lazy generation) to avoid full rebuilds on content-heavy sites.
- Streaming SSR (renderToNodeStream) reduces TTFB vs. renderToString; prefer it when server infrastructure supports chunked transfer.
- React Server Components complement SSR -- they are not a replacement. Use them for zero-bundle-size server logic.
Performance Optimization
- Always measure before and after. Baseline -> incremental change -> re-measurement. No exceptions.
- Audit third-party libraries for bundle impact before adding them. Case study: replacing react-slick with react-glider saved 78% bundle size.
- Inline critical CSS, defer the rest. Render-blocking CSS delays FCP.
- Use Import on Interaction (facade pattern) for third-party widgets: auth dialogs, chat widgets, analytics.
- Use Import on Visibility (IntersectionObserver) for below-the-fold components.
- Apply the PRPL pattern for HTTP/2: Push critical resources, Render initial route, Pre-cache with service workers, Lazy-load remaining routes.
- Tree shaking only works with ES modules and is blocked by side effects. Set the sideEffects field in package.json.
Loading Priority
- Split bundles at route boundaries first -- natural navigation pauses mask loading latency.
- Preload late-discovered critical resources (fonts, hero images). Prefetch anticipated next-page resources during idle time.
- Align resource loading order to FCP -> LCP -> FID milestones; eliminate dead time between them.
Related References
- Core Web Vitals Case Study (Ch. 30) for end-to-end optimization walkthrough
- Hooks Pattern (Ch. 14) for the universal design pattern bridge
- Islands Architecture (Ch. 31) for the rendering strategy frontier
- PRPL Pattern (Ch. 39) for HTTP/2-optimized delivery
- Loading Sequence Optimization (Ch. 32) for resource priority ordering