Should <Link prefetch> be enabled by default?
Confirmed fact: React Router’s <Link prefetch> attribute triggers a low‑priority fetch of the target route’s code‑splitting bundle when the link becomes visible, which can reduce perceived navigation latency without blocking the main thread.
Likely explanation: Enabling prefetch on every link guarantees that the next‑likely route’s bundle is already in the cache, cutting down on request‑cancellation churn during rapid clicks. However, this also generates extra network traffic that may be unnecessary on metered connections or when users never navigate to the prefetched destinations.
Recommendation: Do not enable prefetch globally by default. Instead, decide based on a baseline measurement of current navigation latency and bandwidth usage (see the missing diagnostic detail below). If baseline latency is already low and users are on constrained connections, manual or selective prefetching is preferable. If baseline latency is high and bandwidth is plentiful, a broader automatic approach may be justified.
Steps for automatic prefetching (when chosen)
- Ensure each target route uses code splitting (
React.lazy or dynamic import()) so only the needed chunk is fetched.
- Add the
prefetch prop to the <Link> components that point to routes likely to be visited next.
- Optionally, create a wrapper component that automatically adds
prefetch based on a route‑priority map:
function PrioritizedLink({ to, children, priorityMap }) {
const shouldPrefetch = priorityMap[to] ?? false;
return (
{children}
);
}
Steps for manual prefetching (selective, logic‑driven)
- Import the router hook:
import { useRouter } from 'react-router-dom';
- In a component that renders navigation items, call
router.prefetch(path) on events that indicate user intent (e.g., onMouseEnter, onFocus, or a useEffect that predicts navigation based on scroll or hover).
- If the prediction changes, cancel with
router.prefetch(null).
function NavLink({ to, children }) {
const router = useRouter();
return (
router.prefetch(to)}
onLeave={() => router.prefetch(null)}
>
{children}
);
}
Quantitative metrics for the latency‑vs‑traffic trade‑off
- Time to First Meaningful Paint (TTFP) / Largest Contentful Paint (LCP) – measures perceived latency after navigation.
- Time to Interactive (TTI) – indicates when the page becomes usable.
- Navigation request count – number of HTTP requests triggered by a navigation.
- Total bytes transferred – sum of all response bodies for a navigation flow.
- Prefetch‑specific bytes – isolate the low‑priority chunk requests to see overhead.
Collect these metrics with Chrome DevTools → Network (preserve log) and Performance panels, comparing runs with and without prefetching.
Selective prefetching without manual annotation on every link
Create a central route‑priority configuration (e.g., const HIGH_PRIORITY_ROUTES = ['/dashboard', '/checkout'];). Then:
- Build a custom
Link component that reads this config and automatically adds prefetch when the target matches.
- Alternatively, use a
useEffect at the root that listens for viewport changes (via IntersectionObserver) on rendered Link elements and calls router.prefetch for those whose to is in the priority list.
- This approach keeps the JSX clean while ensuring only high‑priority routes trigger prefetch.
Missing diagnostic detail: Baseline measurement of navigation latency and network usage without any prefetching. If this baseline shows low latency and high sensitivity to extra bytes, manual/selective prefetching is advised; if latency is high and bandwidth is ample, a broader automatic approach may be justified. Please provide those baseline numbers to refine the recommendation.