React Router
React Router is the standard routing library for React. It enables navigation between views, URL parameter handling, and keeps your UI in sync with the URL — all without page reloads. Real-world analogy: Think of React Router like a TV remote. In a traditional website, switching channels (pages) means turning off the TV, walking to the store to buy a new one, and turning it on again (a full page reload). With client-side routing, you press a button on the remote and the channel changes instantly — the TV (your browser) stays on, your app state is preserved, and only the content on screen swaps out.Why Client-Side Routing?
Installation
Basic Setup
1. Wrap Your App with BrowserRouter
2. Define Routes
Link vs NavLink
Link - Basic Navigation
NavLink - Active State Styling
Dynamic Routes (URL Parameters)
Defining Dynamic Routes
Accessing Parameters with useParams
Query Parameters (Search Params)
Programmatic Navigation
useNavigate Hook
Accessing Navigation State
Nested Routes
Create layouts with shared navigation:The
end prop on NavLink ensures it only matches exactly, not partial paths.Protected Routes
Basic Protected Route
Analogy: A protected route is like a security checkpoint at an airport. If you have a valid boarding pass (auth token), you walk through to your gate (the protected page). If not, you are redirected to the ticketing counter (the login page), and the system remembers which gate you were trying to reach so it can send you there after you get your pass.Using Protected Routes
Role-Based Protection
Lazy Loading Routes
Load routes only when needed:Shared Suspense Boundary
useLocation Hook
Access current location information:Scroll Restoration
Reset scroll position on navigation:Error Boundaries with Routes
Common Router Pitfalls
🎯 Practice Exercises
Exercise 1: Blog with Dynamic Routes
Exercise 1: Blog with Dynamic Routes
Summary
Next Steps
In the next chapter, you’ll learn about Optimization & Deployment — making your React apps fast and production-ready!
Interview Deep-Dive
Design a protected route system that handles authentication, role-based access, and redirect-after-login. What are the edge cases?
Design a protected route system that handles authentication, role-based access, and redirect-after-login. What are the edge cases?
Strong Answer:
The architecture has three layers. First, a PrivateRoute wrapper that checks
useAuth(). If not authenticated, it redirects to /login saving the attempted URL in location state. If authenticated, it renders Outlet.Second, a RoleRoute that checks user.role against allowedRoles and redirects to /unauthorized if the role does not match.Third, the login page reads location.state?.from and navigates there after successful login with replace: true.Edge cases from production: the loading state during async auth check must show a spinner, not flash the login page. Token expiry during a session means the next API call returns 401 and the fetch wrapper should clear auth state. Deep link sharing must preserve the full path including query params. The race condition on mount where the route renders before auth state resolves requires gating on loading === false.Follow-up: How do you handle authentication in Next.js differently from a client-side SPA?In a client-side SPA, auth checks happen after JavaScript loads. In Next.js with server rendering, auth checks happen on the server before HTML is sent. You read the auth cookie in a Server Component or middleware and redirect before the protected content reaches the client. This is faster and more secure. The tradeoff is requiring HTTP-only cookies instead of localStorage, which adds server-side cookie management complexity.What is the difference between useParams, useSearchParams, and useLocation? When do you use each?
What is the difference between useParams, useSearchParams, and useLocation? When do you use each?
Strong Answer:
These hooks represent three distinct parts of a URL.
useParams reads path parameters for resource identifiers — the thing you are viewing. useSearchParams reads and writes query parameters for optional view configuration like filters, sort order, and pagination. useLocation gives the complete location object for analytics, breadcrumbs, or navigation state.The design principle: path params for identity (what resource), search params for view configuration (how to display it), location state for ephemeral navigation context (where you came from).A common mistake is putting filter state in component state instead of search params. If a user filters products and refreshes, their filters are lost. Search params make the URL the source of truth.Follow-up: How do you synchronize URL search params with React state without infinite loops?Treat the URL as the single source of truth. Read from useSearchParams directly — do not copy into useState. Update by calling setSearchParams in event handlers. This changes the URL, React Router re-renders, and the component reads new params. One render, one source of truth.The infinite loop trap: putting setSearchParams inside a useEffect that depends on search params creates a cycle. The effect sets params, triggering a re-render, which re-reads params (new reference), which re-triggers the effect. Always set params in event handlers, not effects.