Optimizes React Router navigation performance through route prefetching strategies. Use when eliminating navigation delays with lazy-loaded routes or implementing route preloading patterns.
Eliminates navigation delays in React Router 7 applications with lazy-loaded routes through systematic prefetching strategies.
Use this skill when:
Start with prefetch='intent', add prediction for high-traffic applications.
React Router 7's built-in prefetching eliminates most custom implementation needs. Begin with hover/focus prefetching on navigation links, then layer intelligent prediction for common navigation paths.
┌─ Do routes use React.lazy()? ──No──> No prefetch needed
│
Yes
│
├─ Are users complaining about delays? ──No──> Monitor, no action yet
│
Yes
│
├─ General navigation optimization? ──Yes──> Use prefetch='intent' on Links
│
├─ High-traffic app with known patterns? ──Yes──> Add route-based prediction
│
└─ Mobile/slow connections? ──Yes──> Check navigator.connection before prefetch
React Router 7 provides prefetch support via the Link component's prefetch prop. This uses browser-native <link rel='prefetch'> for background downloads.
Prefetch Modes:
| Mode | Behavior | When to Use |
|---|---|---|
'none' | No prefetching | Low bandwidth priority, rarely navigated |
'intent' | Prefetch on hover/focus (RECOMMEND) | Most navigation links (best balance) |
'render' | Prefetch when link renders | High-probability next routes |
'viewport' | Prefetch when link enters viewport | Long pages with many navigation links |
Basic implementation:
import { Link } from 'react-router-dom';
function Navigation() {
return (
<nav>
{/* Prefetch on hover/focus (recommended default) */}
<Link to="/dashboard" prefetch="intent">Dashboard</Link>
{/* Prefetch immediately when link renders */}
<Link to="/settings" prefetch="render">Settings</Link>
{/* No prefetch for rarely used routes */}
<Link to="/archive" prefetch="none">Archive</Link>
</nav>
);
}
Under the hood: React Router inserts <link rel='prefetch' href='/assets/route-chunk.js'> which downloads at lowest browser priority without blocking.
Uses <link rel='prefetch'> for lowest-priority background downloads.
Pros:
Cons:
Best for: General navigation optimization with minimal effort.
See references/link-prefetch-pattern.md for browser hint details and fallback behavior.
Triggers import() directly when user hovers over navigation links.
Pros:
Cons:
Best for: Critical navigation paths where instant response matters.
See references/eager-loading-pattern.md for implementation with usePrefetchRoutes hook.
Prefetches based on current route and likely next navigation.
Pros:
Cons:
Best for: High-traffic applications with known user flows.
See references/route-prediction-pattern.md for prediction map design.
Update all navigation Link components with prefetch='intent':
// Before
<Link to="/vulnerabilities">Vulnerabilities</Link>
// After
<Link to="/vulnerabilities" prefetch="intent">Vulnerabilities</Link>
Verification:
For applications with >1000 DAU, analyze navigation patterns:
// Example: Track navigation events
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
function useNavigationTracking() {
const location = useLocation();
useEffect(() => {
// Log route + timestamp to analytics
console.log(`Navigated to ${location.pathname}`);
}, [location.pathname]);
}
Build prediction map from top 3 most common next routes per current route.
Create prediction map for common flows:
// src/utils/routePrefetchMap.ts
export const ROUTE_PREFETCH_MAP: Record<string, string[]> = {
'/assets': ['/vulnerabilities', '/jobs'],
'/vulnerabilities': ['/assets', '/insights'],
'/insights': ['/vulnerabilities', '/attacks'],
'/jobs': ['/assets', '/agents'],
'/attacks': ['/vulnerabilities', '/insights'],
};
Implement prefetch hook:
// src/hooks/usePrefetchRoutes.ts
import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import { ROUTE_PREFETCH_MAP } from '../utils/routePrefetchMap';
export function usePrefetchRoutes() {
const location = useLocation();
useEffect(() => {
// Respect user preferences
if (navigator.connection?.saveData) return;
if (navigator.connection?.effectiveType === '2g') return;
// Delay to avoid blocking initial render
const timer = setTimeout(() => {
const routesToPrefetch = ROUTE_PREFETCH_MAP[location.pathname] || [];
routesToPrefetch.forEach(route => {
// Trigger prefetch via link injection
const link = document.createElement('link');
link.rel = 'prefetch';
link.href = route;
document.head.appendChild(link);
});
}, 1000);
return () => clearTimeout(timer);
}, [location.pathname]);
}
See references/implementation-checklist.md for complete setup guide.
Always respect user preferences before prefetching:
function shouldPrefetch(): boolean {
// Check if user enabled data saver
if (navigator.connection?.saveData) return false;
// Avoid prefetch on 2g connections
if (navigator.connection?.effectiveType === '2g') return false;
return true;
}
Why this matters: Prefetching on slow connections or data saver mode wastes user bandwidth and can slow down critical requests.
See references/network-conditions.md for complete navigator.connection API reference.
| Strategy | Bandwidth Cost | Speed Gain | Implementation |
|---|---|---|---|
| Intent (hover/focus) | Zero waste | Fast (hover>200ms) | Trivial |
| Predictive (2-3 routes) | Moderate | Instant | Medium |
| Aggressive (all routes) | High | Always instant | Complex |
Recommendation: Start with intent-based (prefetch='intent'). Add prediction only if analytics show >70% navigation accuracy for specific flows.
Track these metrics to validate prefetching effectiveness:
// Measure navigation timing
const navigationStart = performance.now();
// After route component renders
const navigationEnd = performance.now();
const navigationTime = navigationEnd - navigationStart;
console.log(`Navigation took ${navigationTime}ms`);
Key metrics:
See references/performance-measurement.md for instrumentation setup and monitoring dashboards.
Prefetching works seamlessly with React.lazy() and Vite code splitting:
// Route configuration with lazy loading
const routes = [
{
path: '/dashboard',
lazy: async () => {
const { Dashboard } = await import('./routes/Dashboard');
return { Component: Dashboard };
},
},
];
Coordination with Vite:
route-dashboard-abc123.js)manualChunks optimizes vendor code separatelySee references/code-splitting-integration.md for Vite configuration patterns.
saveData and effectiveType)prefetch='intent' - simplest implementation with best balancesaveData is enabledAfter implementing prefetching:
prefetch='intent' propnavigator.connection.saveData === trueoptimizing-react-performance skill (for navigation optimization)optimizing-vite-builds skill (coordination with code splitting)None - standalone optimization skill.
None - terminal skill providing implementation patterns.
| Skill | Trigger | Purpose |
|---|---|---|
optimizing-react-performance | General React performance optimization | Navigation is one optimization |
optimizing-vite-builds | Code splitting configuration | Coordinate chunk strategy |
optimizing-react-performance - Broader React optimization patterns (includes navigation)optimizing-vite-builds - Code splitting and bundle optimization (complements prefetching)using-modern-react-patterns - React 19 patterns including transitions and concurrent features