Lesson 19 of 30
Fetching inside a mounted component's effect means the spinner only starts after navigation, code loading, and mounting are already done — the fix is starting the fetch earlier, not making it faster.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
What's the concrete problem with the default pattern of fetching a route's data inside a useEffect after the destination component has mounted?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
The default pattern most components use is simple: mount, then fire a fetch in a useEffect. That default has a hidden cost — it creates a strict sequence. Navigation happens, then the destination route's code loads, then the component mounts, and only then does the fetch actually start. The user sees a loading spinner appear right after all of that has already happened, instead of data that's already in flight, or already arrived, by the time it's needed.
Two concrete techniques start the fetch earlier than that:
function PrefetchLink({
href,
cacheKey,
children,
}: {
href: string;
cacheKey: string;
children: React.ReactNode;
}) {
const prefetch = () => {
// Warms a shared cache so the destination route's data may already be
// resolved, or well underway, by the time the user actually clicks.
queryCache.prefetch(cacheKey, () => fetch(`/api${href}`).then((res) => res.json()));
};
return (
<a href={href} onMouseEnter={prefetch} onFocus={prefetch}>
{children}
</a>
);
}
onFocus matters here as much as onMouseEnter — a keyboard user tabbing to a link never triggers a hover event at all, so a prefetch that only listens for the mouse leaves keyboard navigation with no head start.
Route-level loading follows the same underlying idea from a different angle: instead of waiting for a hover, the fetch is declared as part of the route definition itself, so it kicks off the instant navigation is triggered — in parallel with the route's own code loading, rather than after the destination component has already mounted and run its own effect.
"The app feels slow right after clicking a nav link" is a common performance question, and correctly diagnosing it as a sequencing problem, fetch starting too late, rather than a raw speed problem is what separates someone who's actually reasoned about the request waterfall from someone reaching straight for caching or a faster endpoint.