Chapter 13: React Router (v6+)
React Router (v6+) — this is the chapter where your app finally becomes a real multi-page application! No more single page with everything crammed in one component — now we’ll have proper navigation, URLs, dynamic pages, nested layouts, and all the modern routing goodness that React Router v6+ brings.
We’ll go very slowly and clearly, like I’m sitting next to you in Mumbai showing you live on the screen. Every example is complete and ready to copy-paste!
1. Setting Up React Router (v6+)
First, install the latest version:
|
0 1 2 3 4 5 6 |
npm install react-router-dom |
Important: We use v6+ (the current standard in 2026). The API is much cleaner than v5.
2. Basic Setup: BrowserRouter, Routes, Route
The root of your app should wrap everything with <BrowserRouter>.
Update src/main.tsx:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import React from 'react' import ReactDOM from 'react-dom/client' import { BrowserRouter } from 'react-router-dom' import App from './App.tsx' import './index.css' ReactDOM.createRoot(document.getElementById('root')!).render( <React.StrictMode> <BrowserRouter> <App /> </BrowserRouter> </React.StrictMode>, ) |
Now, in src/App.tsx, we define our routes:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import { Routes, Route } from 'react-router-dom'; import Home from './pages/Home'; import About from './pages/About'; import Contact from './pages/Contact'; import NotFound from './pages/NotFound'; function App() { return ( <div> {/* Your header or navbar will go here later */} <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<Contact />} /> {/* Catch-all route for 404 */} <Route path="*" element={<NotFound />} /> </Routes> </div> ); } export default App; |
Create simple page components in src/pages/:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// src/pages/Home.tsx export default function Home() { return ( <div style={{ padding: '60px 40px', textAlign: 'center' }}> <h1 style={{ color: '#646cff' }}>Welcome to My React App!</h1> <p>This is the home page 🚀</p> </div> ); } |
(Do the same for About.tsx, Contact.tsx, and NotFound.tsx with different messages.)
Now run the app — you can navigate by typing in the URL:
- http://localhost:5173/ → Home
- http://localhost:5173/about → About
- http://localhost:5173/anything → 404 page
3. Link vs NavLink – Navigation Without Page Reload
We never use <a href=”/about”> — that causes full page reload. Instead we use Link or NavLink.
Create a simple Navbar: src/components/Navbar.tsx
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
import { Link, NavLink } from 'react-router-dom'; function Navbar() { return ( <nav style={{ background: '#646cff', padding: '16px', display: 'flex', gap: '30px', justifyContent: 'center', boxShadow: '0 2px 10px rgba(0,0,0,0.2)' }}> {/* Basic Link */} <Link to="/" style={{ color: 'white', textDecoration: 'none', fontSize: '18px' }} > Home </Link> {/* NavLink - automatically adds active class */} <NavLink to="/about" style={({ isActive }) => ({ color: isActive ? '#ffd700' : 'white', textDecoration: 'none', fontSize: '18px', fontWeight: isActive ? 'bold' : 'normal' })} > About </NavLink> <NavLink to="/contact" style={({ isActive }) => ({ color: isActive ? '#ffd700' : 'white', textDecoration: 'none', fontSize: '18px', fontWeight: isActive ? 'bold' : 'normal' })} > Contact </NavLink> </nav> ); } export default Navbar; |
Update App.tsx to include the navbar:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import Navbar from './components/Navbar'; // ... other imports function App() { return ( <> <Navbar /> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<Contact />} /> <Route path="*" element={<NotFound />} /> </Routes> </> ); } |
Link vs NavLink:
- Link → simple navigation
- NavLink → adds isActive prop so you can style active links (very common for navbars)
4. Dynamic Routes & URL Parameters (useParams)
Let’s create a User Profile page with dynamic URL: /users/123
Update App.tsx:
|
0 1 2 3 4 5 6 |
<Route path="/users/:userId" element={<UserProfile />} /> |
Create src/pages/UserProfile.tsx
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import { useParams } from 'react-router-dom'; function UserProfile() { const { userId } = useParams(); // ← gets the :userId from URL return ( <div style={{ padding: '60px 40px', textAlign: 'center' }}> <h1 style={{ color: '#646cff' }}>User Profile</h1> <p>Viewing user with ID: <strong>{userId}</strong></p> <p>In real app → fetch user data using this ID</p> </div> ); } export default UserProfile; |
Now go to /users/42 → you’ll see “Viewing user with ID: 42”
5. Nested Routes (Layouts & Children)
Real apps often have shared layouts (sidebar + header) with pages inside.
Create a layout: src/layouts/MainLayout.tsx
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import { Outlet } from 'react-router-dom'; import Navbar from '../components/Navbar'; function MainLayout() { return ( <> <Navbar /> <main style={{ minHeight: 'calc(100vh - 80px)' }}> <Outlet /> {/* ← All child routes render here */} </main> <footer style={{ background: '#333', color: 'white', textAlign: 'center', padding: '20px' }}> © 2026 Webliance - Learning React </footer> </> ); } export default MainLayout; |
Update App.tsx to use nested routes:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
import MainLayout from './layouts/MainLayout'; function App() { return ( <Routes> <Route element={<MainLayout />}> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/contact" element={<Contact />} /> <Route path="/users/:userId" element={<UserProfile />} /> </Route> {/* 404 outside layout */} <Route path="*" element={<NotFound />} /> </Routes> ); } |
Now all pages (except 404) share the navbar + footer!
6. useNavigate – Programmatic Navigation
useNavigate lets you navigate from code (after form submit, button click, etc.)
Example in Contact.tsx:
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
import { useNavigate } from 'react-router-dom'; function Contact() { const navigate = useNavigate(); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); // Simulate form submit alert('Message sent!'); navigate('/'); // ← redirect to home }; return ( <div style={{ padding: '60px 40px' }}> <h1>Contact Us</h1> <form onSubmit={handleSubmit}> <input type="text" placeholder="Your name" style={{ padding: '12px', margin: '10px 0', width: '300px' }} /> <br /> <button type="submit" style={{ padding: '12px 24px', background: '#646cff', color: 'white', border: 'none' }}> Send & Go Home </button> </form> </div> ); } |
7. useSearchParams – Reading & Setting URL Query Strings
Example: Search page with query ?q=react
|
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import { useSearchParams } from 'react-router-dom'; function Search() { const [searchParams, setSearchParams] = useSearchParams(); const query = searchParams.get('q') || ''; const handleSearch = (e: React.ChangeEvent<HTMLInputElement>) => { setSearchParams({ q: e.target.value }); }; return ( <div style={{ padding: '60px 40px' }}> <h1>Search</h1> <input type="text" value={query} onChange={handleSearch} placeholder="Search something..." style={{ padding: '12px', width: '400px', fontSize: '18px' }} /> <p>Current search: <strong>{query || '(empty)'}</strong></p> </div> ); } |
Add route: <Route path=”/search” element={<Search />} />
Now go to /search?q=react → input is filled, URL updates live!
Summary – Chapter 13 Key Takeaways
- Wrap app in <BrowserRouter>
- Use <Routes> + <Route path=”…” element={<Component />} />
- <Link> for simple links, <NavLink> for active styling
- Dynamic routes: path=”/users/:id” → useParams()
- Nested routes + <Outlet /> for layouts
- useNavigate() for programmatic navigation
- useSearchParams() for query strings
Mini Homework
- Create a small app with:
- Navbar
- Home, About, Contact pages
- /users/:id dynamic user page
- /search page with query params
- Bonus: Add a “Go to random user” button that uses useNavigate
