Frontend Architecture
Data fetching: multiple-choice review
Six questions that cut across the whole unit. Each one mirrors a call you make in a real perf review — not a definition to recite, but a tradeoff to weigh against an LCP budget and a stale-data risk.
Confirm you can connect fetch location, waterfalls, RSC streaming, the client cache, and multi-layer invalidation into one decision: which round-trips are on the critical path, and what each fix actually buys.
A product page renders its title (the LCP element) from a client useEffect fetch. LCP is 2.9s. The team adds a loading skeleton and bumps the CDN cache TTL. LCP barely moves. What is the actual fix?
A profile page fetches user (200ms), posts (300ms), and followers (150ms) — all independent — via three nested useEffect components. Total is ~650ms. Why, and what bounds it to ~300ms?
A team marks every component 'use client' in a Next.js App Router app, then complains RSC gave them no bundle win. What happened?
An RSC page fetches data server-side, then a client component calls useQuery for the same data on mount — every page load does two round-trips for one dataset. What is the correct fix?
A search-as-you-type box fires a fetch per keystroke. The user types 'react' but sees results for 'reac'. None of the queries error. Root cause and best fix?
After a mutation updates a product, the server revalidates its cache but users still see the old price for several minutes. The Server Function called revalidateTag correctly. What was missed?
The through-line across the unit is one map of the critical path. Fetch location decides how many round-trips precede LCP — server fetch collapses them, client fetch after JS stacks them. Waterfalls re-serialise independent fetches through the render cascade; Promise.all and sibling RSC components cap them at the slowest. RSC ships zero JS only for components that stay server-side, and Suspense streaming buys a low TTFB. The client cache (SWR semantics, single-flight, optimistic snapshots) governs revisits and interactions, while AbortController kills races. And every mutation must invalidate every cache layer it touches — server revalidation alone leaves the browser stale.