Skip to content
AyoKoding

Overview

Prerequisites

  • Prior topics: 14 · Frontend Essentials -- the component model (state, props, one-way data flow, keyed lists), controlled validated forms, basic ARIA and keyboard patterns, and discriminated-union UI state, assumed throughout; 13 · Just Enough TypeScript -- generics, unions, and narrowing, the raw material co-33 turns into typed components; and 15 · Software Testing -- Testing-Library component tests and the shape of an e2e smoke, which Examples 76-78 and the capstone build directly on.
  • Tools & environment: a macOS/Linux terminal; Node.js + npm; TypeScript (tsc 5.8) and tsx to run every worked example from the CLI. No running dev server, browser, or installed framework is required for any single example -- React, the browser DOM, and framework mechanics (RSC, SSR, signals, service workers) are modeled in pure TypeScript, so every "Output" block is a real captured run. The capstone additionally uses Vitest + @testing-library/dom.
  • Assumed knowledge: building a typed component with state + an accessible form (topic 14); running a component test from the CLI (topic 15); reading a TypeScript union and a generic signature (topic 13).

Why this exists -- the big idea

The problem before the solution: a UI that renders correctly can still fail its users -- slow to paint, janky to interact, inaccessible to a screen reader, and impossible to reason about once state sprawls. The one idea worth keeping if you forget everything else: the frontend's hard problems are state and time -- derive the UI from a single source of state, push data fetching and caching to well-defined edges, and measure performance instead of guessing at it.

Cross-cutting big ideas, taught here and carried through every tier: taming-state -- state-at-scale is the central difficulty of a real frontend, and the client-vs-server cache split (co-15) plus the global-store decision (co-16) are both state-taming moves; consistency-latency- throughput -- Core Web Vitals (co-08) and the rendering-strategy choice (co-01 through co-07) are latency/throughput trade-offs wearing a frontend vocabulary.

How this topic's examples are organized

  • Beginner (Examples 1-28) -- the four rendering strategies (CSR, SSR, SSG, streaming), hydration and its mismatch warning, islands and React Server Components, the Core Web Vitals triad (LCP, INP, CLS) with their current 2026 thresholds, the critical rendering path, code splitting and tree shaking, the Rules of Hooks, useEffect semantics (after paint, cleanup, deps), useMemo/ useCallback, reconciliation and keys, and the controlled-input rule.
  • Intermediate (Examples 29-56) -- uncontrolled inputs and the no-switch rule, the client-vs- server cache split (caching, invalidation, optimistic rollback), when to reach for Redux, memoized selectors, a hand-built virtual-DOM diff, reconciliation by element type, fine-grained signals, semantic landmarks, an ARIA tabs widget, roving tabindex and a focus trap, live regions, accessible form validation and error summaries, CSS Modules vs Tailwind vs specificity, HTTP caching with stale-while-revalidate, a service worker, and performance budgets with bundle analysis.
  • Advanced (Examples 57-80) -- data waterfalls and prefetching, Suspense-for-data via use() versus the useEffect-fetch trap, image optimization, edge rendering and its Web-API subset, discriminated-union state with exhaustive compile-time narrowing, generic and precisely-typed components, the PWA app shell / installability / offline fallback, i18n with Intl and message catalogs and RTL, behaviour-based Testing-Library queries, a user-event interaction test, a Playwright e2e smoke, an error boundary, and a closing capstone-preview assembly of a searchable, paginated dashboard.
  • Capstone -- a four-step build of that dashboard with SSR/streaming, cached fetching + an optimistic update that rolls back, an ARIA-correct widget, and component + e2e tests.

Every example cites the co-NN concept it exercises, and every React/browser/framework claim traces to react.dev, web.dev, the W3C, MDN, and the TypeScript Handbook, per the syllabus's DD-35 citations.

%% Color Palette: Blue #0173B2, Orange #DE8F05, Teal #029E73, Purple #CC78BC, Brown #CA9161, Gray #808080
%% Six concept clusters, in the order this page teaches them (co-01 through co-37)
graph TD
    A["Rendering strategies:<br/>CSR, SSR, SSG, streaming,<br/>hydration, islands, RSC<br/>co-01 to co-07"]:::blue
    B["Core Web Vitals &<br/>the critical path:<br/>LCP, INP, CLS, splitting,<br/>tree shaking<br/>co-08 to co-14"]:::orange
    C["State at scale:<br/>cache vs client, Redux,<br/>hooks, reconciliation,<br/>virtual DOM, signals<br/>co-15 to co-22"]:::teal
    D["Accessibility:<br/>WCAG, focus, forms,<br/>CSS at scale<br/>co-23 to co-29"]:::purple
    E["Data, media & edge:<br/>fetching, images,<br/>edge, TS, PWA, i18n<br/>co-30 to co-35"]:::brown
    F["Testing & resilience:<br/>behaviour tests, e2e,<br/>error boundary<br/>co-36 to co-37"]:::gray
 
    A --> B
    B --> C
    C --> D
    D --> E
    E --> F
 
    classDef blue fill:#0173B2,stroke:#000000,color:#FFFFFF,stroke-width:2px
    classDef orange fill:#DE8F05,stroke:#000000,color:#FFFFFF,stroke-width:2px
    classDef teal fill:#029E73,stroke:#000000,color:#FFFFFF,stroke-width:2px
    classDef purple fill:#CC78BC,stroke:#000000,color:#FFFFFF,stroke-width:2px
    classDef brown fill:#CA9161,stroke:#000000,color:#FFFFFF,stroke-width:2px
    classDef gray fill:#808080,stroke:#000000,color:#FFFFFF,stroke-width:2px

Concepts

Every worked example in this topic's follow-up pages cites the co-NN concept it exercises -- this section is the 1:1 reference those citations point back to. Read it in order: rendering strategies come first because every performance and state concept that follows describes something happening inside a page rendered one of those ways.

co-01 · rendering-csr

Client-side rendering: the browser boots a JS bundle and renders into an empty shell -- there is no content before the bundle runs.

Why it matters: CSR's blank-shell cost (a crawler or no-JS user sees nothing until JS executes) is the problem every other rendering strategy exists to solve.

Verify it: Example 1 shows the pre-JS DOM is empty, and the bundle fills it.

co-02 · rendering-ssr

Server-side rendering: the server returns fully-formed HTML per request, so the content is present before any JavaScript runs.

Why it matters: SSR fixes CSR's blank shell for first paint and crawlability, at the cost of server work on every request.

Verify it: Example 2 returns complete HTML with content baked in, pre-JS.

co-03 · rendering-ssg

Static site generation: pages are pre-rendered to HTML at build time and served as static files, identical for every visitor.

Why it matters: SSG is the cheapest, most cacheable strategy -- a CDN can serve the files forever -- but the content is fixed until the next build.

Verify it: Example 3 shows two requests reading the same byte-identical pre-built file.

co-04 · streaming-ssr

Streaming SSR sends HTML in chunks with <Suspense> fallbacks as async work resolves, so the browser paints the shell before the slowest data is ready.

Why it matters: streaming keeps one slow fetch from blocking the entire page's first paint.

Verify it: Example 4 shows the fallback chunk streaming before the resolved content.

co-05 · hydration

Hydration attaches React's event handling to server-generated HTML via hydrateRoot, reusing the existing DOM instead of re-rendering it.

Why it matters: hydration turns a readable server-rendered page into an interactive one without rebuilding the DOM; a mismatch between server and client output warns and recovers.

Verify it: Example 5 attaches handlers to existing HTML; Example 6 warns on a server/client mismatch.

co-06 · islands-architecture

Islands architecture ships mostly-static HTML with small, independently-hydrated interactive islands (Astro), so only the islands contribute JavaScript bytes.

Why it matters: islands get interactivity where needed without paying CSR's whole-page JS cost.

Verify it: Example 7 ships JS only to the one interactive island.

co-07 · react-server-components

React Server Components split the tree into server components (default, no client JS) and client components; 'use client' marks the module-tree boundary, not the render tree.

Why it matters: keeping most of a tree server-side keeps the client bundle small while still punching interactive holes where needed.

Verify it: Example 8 marks the 'use client' module boundary; Example 9 ships no client JS for a server component.

co-08 · core-web-vitals

Core Web Vitals are the LCP/INP/CLS triad measuring loading, responsiveness, and visual stability. INP replaced FID as a stable Core Web Vital in March 2024.

Why it matters: the triad is the user-experience scoreboard -- a page that "works" can still score poorly here, and the scores are what search and CrUX rank on.

Verify it: Examples 10-13 measure LCP, INP, CLS, and print the current threshold table.

co-09 · lcp

Largest Contentful Paint measures loading: the time of the largest text block or image to paint. Good is at or below 2.5 s at the 75th percentile.

Why it matters: LCP names the specific element that bottlenecks loading, so you know what to optimize.

Verify it: Example 10 identifies the LCP element and its time.

co-10 · inp

Interaction to Next Paint measures responsiveness: the latency from a user input to the next painted frame; a page's INP is its worst interaction. Good is at or below 200 ms.

Why it matters: INP catches jank on later interactions that the retired FID ignored.

Verify it: Example 11 measures the worst interaction's latency.

co-11 · cls

Cumulative Layout Shift measures visual stability: how much visible content jumps. Reserving space for late content keeps it near zero. Good is at or below 0.1.

Why it matters: CLS quantifies the jank of content jumping under the user -- usually fixable by reserving dimensions up front.

Verify it: Example 12 drops CLS to zero by reserving space; Example 63 applies the same fix to images.

co-12 · critical-rendering-path

CSS is render-blocking; the render tree needs both the DOM and the CSSOM, so a blocking stylesheet delays first paint until the CSSOM is built.

Why it matters: the size and chaining of render-blocking CSS directly controls first paint.

Verify it: Example 14 shows blocking CSS delaying first paint; Example 15 speeds it by inlining critical CSS.

co-13 · code-splitting

React.lazy + <Suspense> and route-based splitting defer non-critical code into chunks loaded on demand, keeping the initial bundle small.

Why it matters: splitting turns one giant bundle into many small ones, so a heavy route never enters the initial download.

Verify it: Example 16 lazily loads a chunk on first render; Example 17 splits per route.

co-14 · tree-shaking

Tree shaking eliminates dead code through static ES-module analysis: an export nothing imports is dropped from the bundle.

Why it matters: tree shaking keeps the bundle lean as the codebase grows, for free, because ES module imports/exports are statically analyzable.

Verify it: Example 18 drops an unused export from the bundle.

co-15 · client-vs-server-state

Separate client UI state from the server cache (TanStack Query), with invalidation driving refetches and optimistic updates that roll back on failure.

Why it matters: conflating the two causes redundant refetches and lost UI state; separating them gives a clean server-data layer with caching and convergence.

Verify it: Examples 31-34 cover caching, the client/server split, invalidation, and rollback.

co-16 · when-redux

Reach for a global store (Redux Toolkit) only for large, frequently-updated shared state -- not for every piece of state.

Why it matters: Redux's machinery is overhead you should pay only when the scale of shared state justifies it; most state is better local or in a server cache.

Verify it: Example 35 models a slice, a reducer, and a selector.

co-17 · rules-of-hooks

Call Hooks only at the top level (not in loops/conditions/nested functions) and only from React function components or custom Hooks.

Why it matters: a conditional hook breaks the call-order indexing React relies on, silently corrupting state.

Verify it: Example 19 lints a conditional hook violation; Example 20 shows state-then-re-render.

co-18 · useeffect-semantics

Effects run after paint, clean up before re-run/unmount, and re-run only when a dependency changes by Object.is.

Why it matters: effects run after paint, so they are safe for non-blocking external sync; cleanup prevents leaks; the deps array gates re-runs.

Verify it: Examples 21-23 cover the after-paint ordering, cleanup, and dependency gating.

co-19 · usememo-usecallback

useMemo caches an expensive value and useCallback a stable function reference between renders, recomputing/recreating only on dependency change.

Why it matters: these are targeted performance tools (especially for memoized children), not default wrappers.

Verify it: Examples 24-25 cover useMemo caching and useCallback stability; Example 36 applies the idea to a memoized selector.

co-20 · reconciliation-keys

React identifies elements by tree position; keys give list items stable identity, so a reordered item keeps its node and its state.

Why it matters: stable keys let React reuse nodes on reorder; unstable keys recreate nodes and lose per-item state.

Verify it: Examples 26-27 contrast stable keys (state preserved) with random keys (state lost).

co-21 · virtual-dom

A virtual DOM diffs a virtual-node tree and patches only the changed real DOM nodes, using an O(n) heuristic.

Why it matters: the diff minimizes expensive DOM writes, which is what makes declarative render code affordable.

Verify it: Example 37 emits only the delta between two trees.

co-22 · signals-fine-grained

A .value signal with automatic dependency tracking updates only its dependents, with no full component re-render (Preact/Solid).

Why it matters: fine-grained reactivity updates just the bound DOM, so the parent component never re-runs.

Verify it: Examples 40-42 cover basic signals, computed signals, and the no-parent-rerender payoff.

co-23 · wcag-accessibility

WCAG 2.2 (9 new success criteria versus 2.1), semantic HTML, ARIA roles, and live regions are the accessibility baseline.

Why it matters: semantic landmarks and correct ARIA expose structure and widget semantics that styling alone cannot.

Verify it: Examples 43-44 cover landmarks and an ARIA tabs widget; Example 47 covers live regions.

co-24 · focus-management

document.activeElement, roving tabindex, aria-activedescendant, and focus traps make composite widgets keyboard-operable.

Why it matters: a modal that does not trap focus leaks keyboard users to hidden background controls.

Verify it: Example 45 roves tabindex; Example 46 traps focus inside a dialog.

co-25 · controlled-vs-uncontrolled

A controlled input owns its value in state; an uncontrolled one is read via a ref; an input cannot switch modes mid-life.

Why it matters: state-as-source-of-truth makes validation and formatting straightforward; a mode switch is a bug.

Verify it: Examples 28-30 cover controlled, uncontrolled, and the no-switch warning.

co-26 · accessible-forms

required/aria-required, aria-invalid, aria-describedby, and a focus-moving error summary are the accessible-form baseline.

Why it matters: an error must be programmatically associated with its input, not just visible.

Verify it: Example 48 wires aria-invalid + aria-describedby; Example 49 moves focus to a summary.

co-27 · performance-budget

A performance budget enforces limits on bundle size, request count, and timing as a CI gate.

Why it matters: an enforced budget blocks size regressions the way a failing test blocks a code regression.

Verify it: Examples 55-56 cover a failing budget check and per-dependency bundle analysis.

co-28 · http-caching-swr

Cache-Control with stale-while-revalidate (RFC 5861) and service-worker caching serve stale content while revalidating, and assets offline.

Why it matters: SWR gives instant responses (stale) while refreshing in the background.

Verify it: Example 53 serves stale-while-revalidating; Example 54 caches assets offline.

co-29 · css-at-scale

CSS Modules (locally scoped) and utility-first (Tailwind) solve CSS's global-namespace problem; the cascade/specificity ID--CLASS--TYPE model decides conflicts.

Why it matters: scoping and understanding specificity prevent styles from clobbering each other as the codebase grows.

Verify it: Examples 50-52 cover CSS Modules, Tailwind, and a specificity conflict.

co-30 · data-fetching-patterns

Avoid request waterfalls by parallelizing/prefetching; Suspense-for-data triggers on use(), not on a useEffect fetch.

Why it matters: waterfalls multiply latency serially; the wrong data-loading path silently defeats Suspense.

Verify it: Examples 57-60 cover waterfalls, prefetching, use() under Suspense, and the useEffect-fetch trap.

co-31 · image-optimization

Responsive srcset/sizes, lazy-by-default loading, and reserved dimensions keep image bytes, timing, and layout shifts in check.

Why it matters: images are usually the heaviest assets; the right source, deferred loading, and reserved boxes together control bytes, LCP, and CLS.

Verify it: Examples 61-63 cover srcset, lazy defaults, and CLS prevention.

co-32 · edge-rendering

Render at the CDN edge in a V8-isolate Web-API subset runtime, selected with runtime: 'edge'.

Why it matters: edge rendering cuts latency by running near the user, with the trade-off of a constrained API set.

Verify it: Example 64 opts into the edge runtime; Example 65 shows a Node-only API rejected there.

co-33 · typescript-frontend

Discriminated unions for state, generics in components, and precise required/optional prop typing make impossible states unrepresentable and missing cases compile errors.

Why it matters: precise typing catches whole classes of bugs (impossible states, forgotten cases, missing props) at compile time.

Verify it: Examples 66-69 cover the union, exhaustive narrowing, a generic component, and precise prop typing.

co-34 · pwa-service-worker

Offline caching, the app-shell model, and installability via a web manifest make a site resilient and installable.

Why it matters: a service worker plus a manifest turns a site into a fast, offline-capable, installable app.

Verify it: Examples 70-72 cover the app shell, installability, and offline fallback; Example 54 covers asset caching.

co-35 · i18n

Locale-aware Intl formatting, message catalogs with interpolation, and RTL layout adapt the UI to multiple languages and directions.

Why it matters: correct i18n (formats, externalized strings, logical CSS for RTL) serves users across locales without hand-built formatting or duplicated stylesheets.

Verify it: Examples 73-75 cover Intl, a message catalog, and an RTL-aware layout.

co-36 · testing-behaviour

Test the way software is used (Testing-Library role/text queries + user-event) plus a Playwright e2e smoke of the critical path.

Why it matters: behaviour-based tests are robust to refactors and give confidence real users can use the feature; an e2e smoke verifies the assembled system.

Verify it: Examples 76-78 cover behaviour queries, a user-event flow, and a Playwright smoke.

co-37 · error-boundary

An error boundary catches a render error in a subtree and shows a fallback instead of crashing the whole app.

Why it matters: a boundary localizes a render failure so the rest of the app keeps running.

Verify it: Example 79 catches a render error and renders a fallback.

Examples by Level

Beginner (Examples 1–28)

Intermediate (Examples 29–56)

Advanced (Examples 57–80)


← Previous: Overview · Next: Beginner Examples

Last updated July 28, 2026

Command Palette

Search for a command to run...