Lesson 56 of 80
React itself has no idea what a URL is. React Router is what turns a component tree into an app with real, bookmarkable pages — without a full page reload on every click.
14 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.
This topic is about judgment and practical tradeoffs more than a single right answer — a mock interview is the better way to test yourself on it.
Be interviewed on this →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
React renders components. It has no built-in concept of "the URL says /profile/42, so show the profile page." Left alone, a React app is one page — every "navigation" would just be conditionally rendering different JSX based on some view state variable, and the browser's address bar, back button, and bookmarking would all be lies.
React Router fills that gap for apps that aren't built on a meta-framework like Next.js (which has its own file-based router baked in — more on that distinction below). It watches the URL, matches it against a route table you define, and renders the component for the matching route. Clicking a <Link> updates the URL and swaps components without asking the browser for a new HTML document — that's what "client-side routing" means, and it's why navigation feels instant instead of triggering a full white-flash reload.
import { BrowserRouter, Routes, Route, Link, useNavigate, useParams } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<nav>
<Link to="/">Home</Link>
<Link to="/products/42">Product 42</Link>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products/:id" element={<ProductPage />} />
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
function ProductPage() {
const { id } = useParams(); // reads ":id" from the matched URL
const navigate = useNavigate(); // imperative navigation, e.g. after an action
return (
<div>
<h1>Product {id}</h1>
<button onClick={() => navigate("/")}>Back to home</button>
</div>
);
}
Three pieces do all the work. <Routes> + <Route> is the table: given the current URL, which component renders. <Link to="..."> renders an <a> under the hood but intercepts the click to update the URL via the History API instead of letting the browser navigate for real. useParams and useNavigate are the two hooks you'll reach for constantly — reading dynamic segments out of the matched path, and navigating in response to something happening in code (a form submit, a timeout, a redirect after login) rather than a user clicking a link.
useNavigate doesn't replace <Link> — it complements it. Use <Link> for anything a user clicks; use useNavigate only for navigation triggered by code (after a successful form submit, after a timer, after an auth check). Wrapping a clickable element's onClick around navigate() when a <Link> would do loses you right-click-to-open-in-new-tab and other native anchor behavior for free.<Route> elements from an array, conditionally include one based on a feature flag, or nest them (the next lesson covers nested routes and <Outlet> specifically).React Router doesn't invent navigation from nothing — it's a structured wrapper around the browser's native History API (pushState, popstate), which has let JavaScript change the URL without a reload since long before React existed. Understanding that the "magic" is really just intercepting clicks and calling that native API demystifies most of what feels special about client-side routing.