Router
By the end of this lesson you'll be able to turn a single React component into a multi-page app — defining routes, linking between pages without reloads, reading data out of the URL, redirecting in code, sharing layouts with nested routes, and showing a proper 404 page.
Learn Python, JavaScript, Java and more with free interactive lessons, real projects and AI-powered help. Beginner-friendly.
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
1. Setup & Basic Routes
A router's one job is to look at the current URL and show the matching component. You switch routing on by wrapping your whole app in once (usually in main.jsx ). Then you list your pages inside , one per page, each with a path and the element to render. Read this worked example carefully — every line is commented.
The special path="*" route matches any URL no other route caught, so it's your 404 page — and it goes last. Now run the logic a router uses to pick a route. This is plain JS you can execute:
Your turn. The matcher below is almost done — fill in the one blank so unknown URLs fall through to the 404, then run it and check the output.
2. Linking Between Pages
Inside a routed app you must never use a plain to move between your own pages — that makes the browser throw your app away and reload the whole thing from the server, losing all React state. Use instead: it swaps the page in JavaScript, instantly. is the same thing but it knows when it points at the current page, so you can style the active link.
A normal anchor tag tells the browser "go fetch this URL from the server". The browser tears down the current page, downloads everything again, and re-runs your whole React app from scratch — so any state (a half-filled form, a scroll position, a logged-in flag held in memory) vanishes, and there's a visible flash.
intercepts the click, updates the URL bar with the History API, and just renders the new component. No server round-trip, no flash, no lost state. That speed is the entire point of a single-page app.
3. Dynamic Routes & URL Params
You don't write one route per user. Instead you put a placeholder in the path with a colon — /users/:userId — and that :userId matches whatever's in that slot. Inside the component you read it with the useParams() hook. The key you destructure must match the name after the colon, and the value always comes back as a string .
Now run the actual logic useParams performs: it splits the route pattern and the real URL into pieces and, wherever the pattern has a :name , it grabs the value from the same slot. Fill in the three blanks:
4. Programmatic Navigation
Sometimes you need to change pages from code rather than from a click — for example, redirecting to /dashboard after a successful login. The useNavigate() hook gives you a navigate function: call navigate('/somewhere') and you're there.
Use {' '} after login so the login page isn't left in the history (otherwise pressing Back drops the user right back on it). And navigate(-1) is the same as clicking the browser's Back button.
5. Nested Routes & Outlet
Most apps share a frame across several pages — a dashboard with a fixed sidebar, say. Rather than repeat that sidebar in every component, you nest child routes inside a parent route. The parent renders a shared layout containing an , and React Router drops the matched child page into that slot. The special index route is what shows at the parent's exact path.
Now /dashboard/settings renders DashboardLayout with Settings inside its . The sidebar never re-mounts; only the outlet's contents change as you click around.
No blanks this time — just a brief and an outline. Routers keep a history array so Back works; you'll build a miniature version with push , replace, and pop. Run it and check your output against the expected lines in the comments.
No. React itself has no concept of URLs or pages. React Router is a separate library you add with npm install react-router-dom . It's the de-facto standard for routing in React apps.
Use for things the user clicks (nav bars, buttons that are really links). Use useNavigate when code decides to move — after a form submits, a login succeeds, or a timer fires.
Q: Why is my useParams value a string when the URL had a number?
A URL is just text, so every param arrives as a string. /users/42 gives you "42" . Convert it with Number(userId) if you need to do maths or a strict === comparison.
Q: What's the difference between index and path="" in nested routes?
An index route is what renders at the parent's exact URL (e.g. /dashboard with nothing after it). It's the nested-route way of saying "the default child page."
Practice quiz
Where must you place <BrowserRouter> in a React Router v6 app?
- Around the whole app once, so every Route and router hook lives inside it
- Around each individual <Route> separately
- Only inside the component that calls useNavigate
- It is optional and only needed for dynamic routes
Answer: Around the whole app once, so every Route and router hook lives inside it. BrowserRouter turns on client-side routing for everything nested inside it, so you wrap the entire app exactly once (usually in main.jsx).
Which route definition acts as the catch-all 404 page?
- <Route path="/404" .../>
- <Route path="*" .../> placed last
- <Route path="" .../>
- <Route index .../>
Answer: <Route path="*" .../> placed last. path="*" matches any URL no other route caught. Because routes are read top to bottom, it must come last or it would swallow everything below it.
Why should you use <Link> instead of a plain <a href> for internal navigation?
- <a> tags are not valid inside React components
- <Link> automatically adds query parameters
- <a href> triggers a full page reload that tears down the app and loses state, while <Link> swaps the page in JavaScript
- There is no difference; they behave identically
Answer: <a href> triggers a full page reload that tears down the app and loses state, while <Link> swaps the page in JavaScript. A plain anchor makes the browser refetch and re-run the whole app, losing React state. Link intercepts the click and updates the URL with the History API, keeping state.
Given <Route path="/users/:userId" ...>, how do you read userId inside the component?
- const userId = useParams
- const { userId } = useParams()
- const userId = props.userId
- const { userId } = useNavigate()
Answer: const { userId } = useParams(). useParams() returns an object whose keys match the dynamic segments. The destructured key must exactly match the name after the colon.
A URL param from useParams() for /users/42 comes back as what type?
- A number (42)
- A string ("42")
- An object { value: 42 }
- undefined until parsed
Answer: A string ("42"). URLs are just text, so every param arrives as a string. Use Number(userId) before doing maths or a strict === comparison.
Which hook lets you change the URL from code, e.g. after a login succeeds?
- useParams()
- useNavigate()
- useLocation()
- useRoutes()
Answer: useNavigate(). useNavigate() returns a navigate function: navigate('/dashboard') redirects programmatically rather than from a click.
What does navigate('/dashboard', { replace: true }) do?
- Opens the route in a new tab
- Navigates without adding a new entry to the history stack, so Back won't return to the current page
- Replaces the entire route configuration
- Reloads the page from the server
Answer: Navigates without adding a new entry to the history stack, so Back won't return to the current page. replace: true swaps the current history entry instead of pushing a new one — ideal after login so Back doesn't return to the login form.
In nested routes, where does the matched child route render?
- Wherever you place an <Outlet /> in the parent layout
- Automatically at the bottom of the page
- Inside a <Routes> tag in the child
- It replaces the parent component entirely
Answer: Wherever you place an <Outlet /> in the parent layout. The parent layout renders an <Outlet />, and React Router drops the matched child component into that slot while the surrounding layout stays mounted.
What is the purpose of an index route inside a parent route?
- It renders at the parent's exact path as the default child
- It sets the order routes are evaluated
- It marks the 404 fallback
- It enables lazy loading
Answer: It renders at the parent's exact path as the default child. An index route is what shows at the parent's exact URL (e.g. /dashboard with nothing after it) — the default child page.
What does <NavLink> add over a regular <Link>?
- It performs a full page reload
- It knows whether it points at the current page, so you can style the active link
- It only works for external URLs
- It caches the destination component
Answer: It knows whether it points at the current page, so you can style the active link. NavLink is a Link that's aware of the active route. Its className function receives { isActive } so you can highlight the current page.