Routing with React Router
Implement client-side routing in your React applications.
Understanding React Router: Building Single Page Applications with Navigation
React Router is the standard routing library for React applications. It enables you to build single-page applications with multiple views, allowing users to navigate between different components while maintaining the application state. Think of it as the GPS system for your React app - it helps users navigate to different destinations (components) within your application.
What is Client-Side Routing? Traditional web applications reload the entire page when navigating between different URLs. This creates a jarring experience with page flashes and lost application state. Client-side routing, which React Router provides, updates the URL and renders different components without reloading the page, creating a smooth, app-like experience.
Why React Router?
- Declarative routing: Define routes using JSX components
- Dynamic route matching: Handle parameters and query strings
- Nested routing: Build complex layouts with nested route structures
- History management: Navigate programmatically and handle browser back/forward
- Code splitting: Load components only when needed
Core Components of React Router
- BrowserRouter: The router that uses HTML5 history API
- Routes: Container for all your route definitions
- Route: Defines a mapping between a URL path and a component
- Link: Creates navigation links (replaces anchor tags)
- useNavigate: Hook for programmatic navigation
Installation React Router is not included with React by default. Install it using:
npm install react-router-dom
Real-World Analogy Think of React Router like the floor plan of an office building:
- BrowserRouter is the building itself
- Routes are the hallways connecting different areas
- Route components are the doors to specific rooms
- Link components are the signs pointing to different rooms
- useNavigate is like having a building guide who can take you anywhere
1// 🏢 REACT ROUTER BASICS: Building a Multi-Page SPA23import React from 'react';4import {5 BrowserRouter,6 Routes,7 Route,8 Link,9 useNavigate,10 useLocation,11 NavLink12} from 'react-router-dom';1314// Basic page components15function HomePage() {16 return (17 <div>18 <h1>Home Page</h1>19 <p>Welcome to our React Router demo!</p>20 </div>21 );22}2324function AboutPage() {25 const navigate = useNavigate();2627 return (28 <div>29 <h1>About Us</h1>30 <button onClick={() => navigate('/contact')}>31 Go to Contact32 </button>33 </div>34 );35}3637function ContactPage() {38 const location = useLocation();3940 return (41 <div>42 <h1>Contact</h1>43 <p>Current path: {location.pathname}</p>44 </div>45 );46}4748// Navigation component with NavLink49function Navigation() {50 return (51 <nav>52 <NavLink53 to="/"54 style={({ isActive }) => ({55 color: isActive ? 'red' : 'blue',56 marginRight: '10px'57 })}58 >59 Home60 </NavLink>61 <NavLink62 to="/about"63 style={({ isActive }) => ({64 color: isActive ? 'red' : 'blue',65 marginRight: '10px'66 })}67 >68 About69 </NavLink>70 <NavLink71 to="/contact"72 style={({ isActive }) => ({73 color: isActive ? 'red' : 'blue'74 })}75 >76 Contact77 </NavLink>78 </nav>79 );80}8182// Main App with routing83function App() {84 return (85 <BrowserRouter>86 <Navigation />8788 <Routes>89 <Route path="/" element={<HomePage />} />90 <Route path="/about" element={<AboutPage />} />91 <Route path="/contact" element={<ContactPage />} />92 <Route path="*" element={<h1>404 - Page Not Found</h1>} />93 </Routes>94 </BrowserRouter>95 );96}9798// Programmatic navigation example99function NavigationControls() {100 const navigate = useNavigate();101 const location = useLocation();102103 return (104 <div>105 <p>Current: {location.pathname}</p>106 <button onClick={() => navigate(-1)}>Back</button>107 <button onClick={() => navigate('/')}>Home</button>108 <button onClick={() => navigate('/about', { replace: true })}>109 Replace with About110 </button>111 </div>112 );113}114115export default App;
Dynamic Routes with Parameters: Creating Flexible URLs
Dynamic routes allow you to create flexible URLs that can handle variable content. Instead of creating a separate route for every user, product, or blog post, you can create one dynamic route that handles all of them. This is essential for building scalable applications.
Understanding Route Parameters Route parameters are placeholders in your route paths that get filled with actual values when users navigate. They're denoted with a colon (:) followed by the parameter name.
For example:
/users/:id
matches/users/123
,/users/abc
, etc./products/:category/:id
matches/products/electronics/42
Types of Dynamic Routes
- Single parameter:
/users/:id
- Multiple parameters:
/posts/:year/:month/:slug
- Optional parameters:
/products/:category/:id?
- Wildcard/catch-all:
/docs/*
The useParams Hook React Router provides the useParams hook to access route parameters in your components. It returns an object with key-value pairs of the URL parameters.
Real-World Analogy Think of route parameters like a hotel keycard system:
- The route pattern (
/room/:number
) is like the card reader - The actual URL (
/room/405
) is like a specific keycard - useParams extracts "405" so you know which room to display
Common Use Cases
- User profiles:
/users/:username
- Product details:
/products/:productId
- Blog posts:
/blog/:year/:month/:slug
- Category pages:
/shop/:category
- Search results:
/search/:query
1// 🎯 DYNAMIC ROUTING EXAMPLES23import React, { useState, useEffect } from 'react';4import {5 BrowserRouter,6 Routes,7 Route,8 Link,9 useParams,10 useNavigate,11 useSearchParams12} from 'react-router-dom';1314// Single parameter example15function UserProfile() {16 const { userId } = useParams();17 const users = {18 '1': { name: 'Alice', role: 'Developer' },19 '2': { name: 'Bob', role: 'Designer' }20 };2122 const user = users[userId];23 if (!user) return <div>User not found!</div>;2425 return (26 <div>27 <h1>{user.name}</h1>28 <p>Role: {user.role}</p>29 <Link to="/users/1">Alice</Link>30 <Link to="/users/2">Bob</Link>31 </div>32 );33}3435// Multiple parameters example36function ProductDetails() {37 const { category, productId } = useParams();38 const navigate = useNavigate();3940 return (41 <div>42 <h1>Product {productId} in {category}</h1>43 <button onClick={() => navigate(-1)}>Back</button>44 </div>45 );46}4748// Query parameters example49function SearchPage() {50 const [searchParams, setSearchParams] = useSearchParams();51 const query = searchParams.get('q') || '';5253 const handleSearch = (e) => {54 e.preventDefault();55 const formData = new FormData(e.target);56 setSearchParams({ q: formData.get('query') });57 };5859 return (60 <div>61 <form onSubmit={handleSearch}>62 <input name="query" defaultValue={query} placeholder="Search..." />63 <button type="submit">Search</button>64 </form>65 {query && <p>Results for "{query}"</p>}66 </div>67 );68}6970// Wildcard routes example71function Documentation() {72 const params = useParams();73 const path = params['*'] || 'index';7475 return (76 <div>77 <h1>Docs: {path}</h1>78 <nav>79 <Link to="/docs">Home</Link>80 <Link to="/docs/getting-started">Getting Started</Link>81 <Link to="/docs/api/users">API Users</Link>82 </nav>83 </div>84 );85}8687// Main app with dynamic routes88function App() {89 return (90 <BrowserRouter>91 <Routes>92 <Route path="/" element={<h1>Dynamic Routing</h1>} />93 <Route path="/users/:userId" element={<UserProfile />} />94 <Route path="/products/:category/:productId" element={<ProductDetails />} />95 <Route path="/search" element={<SearchPage />} />96 <Route path="/docs/*" element={<Documentation />} />97 </Routes>98 </BrowserRouter>99 );100}101102export default App;
Nested Routes: Building Hierarchical Application Layouts
Nested routes are a powerful feature that allows you to build complex, hierarchical layouts where child routes render inside parent routes. This mirrors the component composition pattern that makes React so powerful, but applied to routing.
Understanding Nested Routes Nested routes create a parent-child relationship between routes. When a nested route is matched, both the parent and child components render, with the child component appearing where the parent specifies.
The Outlet Component The Outlet component is where child routes render within their parent. Think of it as a placeholder that gets filled with the matching child route's component. It's similar to props.children but specifically for routes.
Benefits of Nested Routes
- Shared layouts: Common UI elements (headers, sidebars) stay consistent
- Hierarchical organization: URLs mirror your UI structure
- Code reusability: Parent components handle shared logic
- Better UX: Partial page updates instead of full refreshes
Real-World Analogy Think of nested routes like Russian nesting dolls (Matryoshka):
- The outer doll (parent route) contains the shell
- Inner dolls (child routes) fit inside at designated spots
- Each level adds its own content while maintaining the outer structure
Common Patterns
- Dashboard layouts with sidebar navigation
- Settings pages with subsections
- Admin panels with multiple management areas
- E-commerce category and product hierarchies
- Multi-step forms with progress indicators
1// 🏗️ NESTED ROUTES EXAMPLE23import React from 'react';4import {5 BrowserRouter,6 Routes,7 Route,8 Link,9 Outlet,10 NavLink11} from 'react-router-dom';1213// Layout component with sidebar14function DashboardLayout() {15 return (16 <div style={{ display: 'flex' }}>17 <aside style={{ width: '200px', backgroundColor: '#f0f0f0', padding: '20px' }}>18 <h2>Dashboard</h2>19 <nav>20 <NavLink to="/dashboard" end style={{ display: 'block', margin: '10px 0' }}>21 Overview22 </NavLink>23 <NavLink to="/dashboard/users" style={{ display: 'block', margin: '10px 0' }}>24 Users25 </NavLink>26 <NavLink to="/dashboard/settings" style={{ display: 'block', margin: '10px 0' }}>27 Settings28 </NavLink>29 </nav>30 </aside>3132 <main style={{ flex: 1, padding: '20px' }}>33 {/* Child routes render here */}34 <Outlet />35 </main>36 </div>37 );38}3940// Dashboard pages41function Overview() {42 return <h1>Dashboard Overview</h1>;43}4445function Users() {46 return (47 <div>48 <h1>Users</h1>49 <nav>50 <Link to="/dashboard/users">All</Link>51 <Link to="/dashboard/users/active">Active</Link>52 </nav>53 <Outlet />54 </div>55 );56}5758function AllUsers() {59 return <p>Showing all users...</p>;60}6162function ActiveUsers() {63 return <p>Showing active users...</p>;64}6566function Settings() {67 return (68 <div>69 <h1>Settings</h1>70 <nav>71 <NavLink to="/dashboard/settings/profile">Profile</NavLink>72 <NavLink to="/dashboard/settings/security">Security</NavLink>73 </nav>74 <Outlet />75 </div>76 );77}7879function ProfileSettings() {80 return <h2>Profile Settings</h2>;81}8283function SecuritySettings() {84 return <h2>Security Settings</h2>;85}8687// App with nested route configuration88function App() {89 return (90 <BrowserRouter>91 <Routes>92 <Route path="/" element={<h1>Home</h1>} />9394 {/* Dashboard routes with nested structure */}95 <Route path="/dashboard" element={<DashboardLayout />}>96 <Route index element={<Overview />} />9798 <Route path="users" element={<Users />}>99 <Route index element={<AllUsers />} />100 <Route path="active" element={<ActiveUsers />} />101 </Route>102103 <Route path="settings" element={<Settings />}>104 <Route path="profile" element={<ProfileSettings />} />105 <Route path="security" element={<SecuritySettings />} />106 </Route>107 </Route>108 </Routes>109 </BrowserRouter>110 );111}112113export default App;
Protected Routes: Securing Your Application with Authentication and Authorization
Protected routes are essential for building secure applications. They prevent unauthorized users from accessing certain parts of your application by checking authentication status and user permissions before rendering components.
Authentication vs Authorization
- Authentication: Verifying who the user is (login status)
- Authorization: Verifying what the user can do (permissions/roles)
Common Protection Patterns
- Login Protection: Redirect to login if not authenticated
- Role-Based Access: Different UI for different user roles
- Permission-Based: Fine-grained control based on specific permissions
- Subscription-Based: Premium features for paying users
- Conditional Rendering: Show/hide UI elements based on auth state
Implementation Strategies
- Higher-Order Components (HOC): Wrap components with auth logic
- Custom Route Components: Create ProtectedRoute components
- Context + Hooks: Centralized auth state management
- Route Guards: Check permissions before navigation
Security Best Practices
- Never trust client-side protection alone
- Always validate permissions on the server
- Store sensitive data securely
- Implement proper session management
- Handle edge cases (expired tokens, network errors)
User Experience Considerations
- Show loading states during auth checks
- Provide clear feedback for unauthorized access
- Remember intended destination after login
- Implement smooth redirects
1// 🔐 PROTECTED ROUTES EXAMPLE23import React, { createContext, useContext, useState } from 'react';4import {5 BrowserRouter,6 Routes,7 Route,8 Navigate,9 useNavigate,10 useLocation,11 Link12} from 'react-router-dom';1314// Authentication Context15const AuthContext = createContext(null);1617function AuthProvider({ children }) {18 const [user, setUser] = useState(null);1920 const login = (username, password) => {21 // Mock authentication22 if (username === 'admin' && password === 'admin') {23 setUser({ username, role: 'admin' });24 return true;25 } else if (username === 'user' && password === 'user') {26 setUser({ username, role: 'user' });27 return true;28 }29 return false;30 };3132 const logout = () => {33 setUser(null);34 };3536 return (37 <AuthContext.Provider value={{ user, login, logout }}>38 {children}39 </AuthContext.Provider>40 );41}4243function useAuth() {44 return useContext(AuthContext);45}4647// Protected Route Component48function ProtectedRoute({ children }) {49 const { user } = useAuth();50 const location = useLocation();5152 if (!user) {53 // Redirect to login and save the attempted location54 return <Navigate to="/login" state={{ from: location }} replace />;55 }5657 return children;58}5960// Role-Based Protected Route61function AdminRoute({ children }) {62 const { user } = useAuth();6364 if (!user) {65 return <Navigate to="/login" replace />;66 }6768 if (user.role !== 'admin') {69 return <Navigate to="/unauthorized" replace />;70 }7172 return children;73}7475// Public Pages76function HomePage() {77 const { user } = useAuth();7879 return (80 <div>81 <h1>Home</h1>82 {user ? (83 <p>Welcome, {user.username}!</p>84 ) : (85 <p>Please login to access protected features.</p>86 )}87 </div>88 );89}9091function LoginPage() {92 const [username, setUsername] = useState('');93 const [password, setPassword] = useState('');94 const { login } = useAuth();95 const navigate = useNavigate();96 const location = useLocation();9798 const from = location.state?.from?.pathname || '/dashboard';99100 const handleSubmit = (e) => {101 e.preventDefault();102 if (login(username, password)) {103 navigate(from, { replace: true });104 } else {105 alert('Invalid credentials');106 }107 };108109 return (110 <div>111 <h1>Login</h1>112 <p>Demo: admin/admin or user/user</p>113 <form onSubmit={handleSubmit}>114 <input115 type="text"116 placeholder="Username"117 value={username}118 onChange={(e) => setUsername(e.target.value)}119 />120 <input121 type="password"122 placeholder="Password"123 value={password}124 onChange={(e) => setPassword(e.target.value)}125 />126 <button type="submit">Login</button>127 </form>128 </div>129 );130}131132// Protected Pages133function Dashboard() {134 const { user } = useAuth();135 return (136 <div>137 <h1>Dashboard</h1>138 <p>Welcome to your dashboard, {user.username}!</p>139 </div>140 );141}142143function AdminPanel() {144 return (145 <div>146 <h1>Admin Panel</h1>147 <p>Only admins can see this page.</p>148 </div>149 );150}151152// Navigation153function Navigation() {154 const { user, logout } = useAuth();155 const navigate = useNavigate();156157 const handleLogout = () => {158 logout();159 navigate('/');160 };161162 return (163 <nav>164 <Link to="/">Home</Link>165 {user ? (166 <>167 <Link to="/dashboard">Dashboard</Link>168 {user.role === 'admin' && <Link to="/admin">Admin</Link>}169 <button onClick={handleLogout}>Logout</button>170 </>171 ) : (172 <Link to="/login">Login</Link>173 )}174 </nav>175 );176}177178// Main App179function App() {180 return (181 <AuthProvider>182 <BrowserRouter>183 <Navigation />184185 <Routes>186 {/* Public routes */}187 <Route path="/" element={<HomePage />} />188 <Route path="/login" element={<LoginPage />} />189190 {/* Protected routes */}191 <Route192 path="/dashboard"193 element={194 <ProtectedRoute>195 <Dashboard />196 </ProtectedRoute>197 }198 />199200 {/* Admin only routes */}201 <Route202 path="/admin"203 element={204 <AdminRoute>205 <AdminPanel />206 </AdminRoute>207 }208 />209210 <Route path="/unauthorized" element={<h1>Unauthorized</h1>} />211 </Routes>212 </BrowserRouter>213 </AuthProvider>214 );215}216217export default App;