awesome-everything RU
↑ Back to the climb

Frontend Architecture

Data fetching: code reading

Crux Read real fetching snippets — a server waterfall, a queryKey, an RSC Suspense layout, and a search race — and pick the behaviour or the highest-leverage fix.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at senior altitude — in orbit
◷ 14 min

Data-fetching bugs are read in code and in the Network panel. Read each snippet, predict the round-trip shape, and choose the fix a senior frontend engineer makes first.

Goal

Practise the loop you run in every fetching review: trace which requests are sequential vs parallel, read a cache key for its identity, spot an RSC waterfall hiding in a loop, and kill a response race at the source.

Snippet 1 — the server component loop

// Server Component — renders a 50-item order list
async function OrderList({ ids }: { ids: string[] }) {
  const orders = [];
  for (const id of ids) {
    orders.push(await fetchOrder(id));   // one await per iteration
  }
  return <ul>{orders.map(o => <Order key={o.id} data={o} />)}</ul>;
}
Quiz

Each fetchOrder takes ~40ms. What is the total fetch time, and what is the fix?

Snippet 2 — the query key

function useProduct(id: string, currency: string) {
  return useQuery({
    queryKey: ['product', id],                 // currency is NOT in the key
    queryFn: () => fetchProduct(id, currency),
  });
}
Quiz

A user switches currency from USD to EUR on the same product. What goes wrong, and why?

Snippet 3 — the RSC layout

// Server Component page
async function ProductPage({ id }) {
  const product = await fetchProduct(id);        // fast, ~50ms
  return (
    <main>
      <h1>{product.name}</h1>
      <Suspense fallback={<ReviewsSkeleton />}>
        <Reviews productId={id} />               {/* slow, ~800ms */}
      </Suspense>
    </main>
  );
}
Quiz

Reviews takes 800ms. When does the user first see the product title, and why?

function useSearch(query: string) {
  const [results, setResults] = useState([]);
  useEffect(() => {
    fetch(`/api/search?q=${query}`)
      .then(r => r.json())
      .then(setResults);                  // no cleanup, no cancellation
  }, [query]);
  return results;
}
Quiz

Under fast typing this intermittently shows results for an earlier query. What is the minimal correct fix?

Recap

Every fetching bug is visible in the code: an await inside a loop is a server-side waterfall — Promise.all bounds it to the slowest call; a queryKey must contain every input that changes the response or the cache serves the wrong entry; a Suspense boundary lets the shell stream at TTFB while slow children resolve independently; and an uncancelled effect fetch races on fast input — an AbortController in the cleanup, or a library that cancels stale keys, makes the latest query win. Read the code, trace the round-trips, fix the structure before reaching for a knob.

Continue the climb ↑Data fetching: collapse the critical path
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.