React Router Cheat Sheet
Complete reference guide for React Router with interactive examples and live playground links
Click on any section to jump directly to it
Installation & Setup
Install React Router
Install React Router package for your React application
# Install React Router v7 (latest)
npm install react-router
# Or with yarn
yarn add react-router
# Or with pnpm
pnpm add react-router
Basic Setup - Declarative Mode
Set up React Router in declarative mode with BrowserRouter
import React from "react";
import ReactDOM from "react-dom/client";
import { BrowserRouter } from "react-router";
import App from "./App";
const root = document.getElementById("root");
ReactDOM.createRoot(root).render(
<BrowserRouter>
<App />
</BrowserRouter>
);
Basic Setup - Data Mode
Set up React Router in data mode with RouterProvider
import React from "react";
import ReactDOM from "react-dom/client";
import { createBrowserRouter, RouterProvider } from "react-router";
import Home from "./components/Home";
import About from "./components/About";
const router = createBrowserRouter([
{
path: "/",
element: <Home />
},
{
path: "/about",
element: <About />
}
]);
const root = document.getElementById("root");
ReactDOM.createRoot(root).render(
<RouterProvider router={router} />
);
Routing Configuration
Basic Routes
Define basic routes using Routes and Route components
import { Routes, Route } from "react-router";
import Home from "./components/Home";
import About from "./components/About";
import Contact from "./components/Contact";
function App() {
return (
<Routes>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
</Routes>
);
}
Nested Routes
Create nested routes with parent-child relationship
import { Routes, Route, Outlet } from "react-router";
// Parent component with Outlet
function Dashboard() {
return (
<div>
<h1>Dashboard</h1>
<nav>
<Link to="/dashboard">Home</Link>
<Link to="/dashboard/settings">Settings</Link>
</nav>
<Outlet /> {/* Child routes render here */}
</div>
);
}
// App routes
function App() {
return (
<Routes>
<Route path="dashboard" element={<Dashboard />}>
<Route index element={<DashboardHome />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
);
}
Dynamic Routes
Handle dynamic URL segments and optional parameters
import { Routes, Route } from "react-router";
function App() {
return (
<Routes>
{/* Single dynamic segment */}
<Route path="users/:userId" element={<User />} />
{/* Multiple dynamic segments */}
<Route path="users/:userId/posts/:postId" element={<Post />} />
{/* Optional segments */}
<Route path="products/:id?" element={<Product />} />
{/* Catch-all routes (splats) */}
<Route path="files/*" element={<FileViewer />} />
</Routes>
);
}
Layout Routes
Use layout routes for shared UI without adding URL segments
function App() {
return (
<Routes>
{/* Layout route without path adds nesting */}
<Route element={<AuthLayout />}>
<Route path="login" element={<Login />} />
<Route path="register" element={<Register />} />
</Route>
{/* Another layout for protected routes */}
<Route element={<ProtectedLayout />}>
<Route path="dashboard" element={<Dashboard />} />
<Route path="profile" element={<Profile />} />
</Route>
</Routes>
);
}
Navigation Components
Link Component
Create navigation links with Link component
import { Link } from "react-router";
function Navigation() {
return (
<nav>
<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>
{/* Link with state */}
<Link to="/dashboard" state={{ from: 'navigation' }}>
Dashboard
</Link>
{/* Relative links */}
<Link to="../parent">Go to Parent</Link>
<Link to="child">Go to Child</Link>
</nav>
);
}
NavLink with Active States
Use NavLink for navigation with active state styling
import { NavLink } from "react-router";
function Navigation() {
return (
<nav>
{/* Automatic .active class */}
<NavLink to="/">Home</NavLink>
{/* Custom active styling with className */}
<NavLink
to="/about"
className={({ isActive }) =>
isActive ? "text-red-500 font-bold" : "text-black"
}
>
About
</NavLink>
{/* Custom active styling with style */}
<NavLink
to="/contact"
style={({ isActive }) => ({
color: isActive ? 'red' : 'black',
fontWeight: isActive ? 'bold' : 'normal'
})}
>
Contact
</NavLink>
{/* Active children callback */}
<NavLink to="/dashboard">
{({ isActive }) => (
<span className={isActive ? "active" : ""}>
{isActive ? "👉" : ""} Dashboard
</span>
)}
</NavLink>
</nav>
);
}
Router Hooks
useNavigate - Programmatic Navigation
Navigate programmatically using useNavigate hook
import { useNavigate } from "react-router";
function LoginForm() {
const navigate = useNavigate();
const handleSubmit = async (formData) => {
try {
await login(formData);
// Navigate to dashboard after successful login
navigate("/dashboard");
// Navigate with replace (replaces current entry)
navigate("/dashboard", { replace: true });
// Navigate back
navigate(-1);
// Navigate forward
navigate(1);
// Navigate with state
navigate("/profile", {
state: { message: "Login successful" }
});
} catch (error) {
console.error("Login failed:", error);
}
};
return (
<form onSubmit={handleSubmit}>
{/* form fields */}
</form>
);
}
useParams - Access URL Parameters
Extract dynamic parameters from the current route
import { useParams } from "react-router";
// For route: /users/:userId/posts/:postId
function PostDetail() {
const params = useParams();
// Access individual parameters
const { userId, postId } = useParams();
// Or access all params
console.log(params); // { userId: "123", postId: "456" }
return (
<div>
<h1>Post {postId}</h1>
<p>By User {userId}</p>
</div>
);
}
// For catch-all routes: /files/*
function FileViewer() {
const { "*": splat } = useParams();
// or
const params = useParams();
const filePath = params["*"];
return <div>Viewing file: {filePath}</div>;
}
useLocation - Access Location Object
Access current location information and state
import { useLocation } from "react-router";
function LocationInfo() {
const location = useLocation();
console.log(location.pathname); // "/dashboard/settings"
console.log(location.search); // "?tab=general&page=2"
console.log(location.hash); // "#section1"
console.log(location.state); // state passed via navigate
console.log(location.key); // unique key for this location
return (
<div>
<h2>Current Path: {location.pathname}</h2>
<p>Query String: {location.search}</p>
{location.state && (
<p>State: {JSON.stringify(location.state)}</p>
)}
</div>
);
}
// Common use cases
function useAnalytics() {
const location = useLocation();
useEffect(() => {
// Track page views
analytics.track(location.pathname);
}, [location]);
}
function ScrollToTop() {
const location = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [location.pathname]);
return null;
}
Search Parameters
useSearchParams - Basic Usage
Read URL search parameters using useSearchParams
import { useSearchParams } from "react-router";
function SearchResults() {
const [searchParams, setSearchParams] = useSearchParams();
// Get individual search parameter
const query = searchParams.get("q");
const page = searchParams.get("page") || "1";
const category = searchParams.get("category");
// Check if parameter exists
const hasFilter = searchParams.has("filter");
// Get all entries
const allParams = Object.fromEntries(searchParams.entries());
console.log(allParams); // { q: "react", page: "2", category: "tech" }
return (
<div>
<h1>Search Results for: {query}</h1>
<p>Page: {page}</p>
<p>Category: {category || "All"}</p>
</div>
);
}
useSearchParams - Setting Parameters
Update URL search parameters while preserving existing ones
import { useSearchParams } from "react-router";
function ProductFilters() {
const [searchParams, setSearchParams] = useSearchParams();
const activeCategory = searchParams.get("category") || "all";
const activeSort = searchParams.get("sort") || "name";
const currentPage = parseInt(searchParams.get("page") || "1");
// Update single parameter (replaces all params)
const setCategory = (category) => {
setSearchParams({ category });
};
// Update multiple parameters (replaces all params)
const applyFilters = (category, sort) => {
setSearchParams({
category,
sort,
page: "1" // reset to first page
});
};
// Preserve existing params while updating
const setPage = (page) => {
const newParams = new URLSearchParams(searchParams);
newParams.set("page", page.toString());
setSearchParams(newParams);
};
// Remove a specific parameter
const removeFilter = (paramName) => {
const newParams = new URLSearchParams(searchParams);
newParams.delete(paramName);
setSearchParams(newParams);
};
return (
<div>
<select
value={activeCategory}
onChange={(e) => setCategory(e.target.value)}
>
<option value="all">All Categories</option>
<option value="electronics">Electronics</option>
<option value="clothing">Clothing</option>
</select>
<button onClick={() => setPage(currentPage + 1)}>
Next Page
</button>
</div>
);
}
Tab Navigation with Search Params
Use search params for tab navigation and state management
import { useSearchParams } from "react-router";
function TabNavigation() {
const [searchParams, setSearchParams] = useSearchParams();
const activeTab = searchParams.get('tab') || 'overview';
const setActiveTab = (tab) => {
const newParams = new URLSearchParams(searchParams);
newParams.set('tab', tab);
setSearchParams(newParams);
};
const tabs = [
{ id: 'overview', label: 'Overview' },
{ id: 'details', label: 'Details' },
{ id: 'reviews', label: 'Reviews' },
];
return (
<div>
{/* Tab Navigation */}
<div className="tab-nav">
{tabs.map(tab => (
<button
key={tab.id}
className={`tab ${activeTab === tab.id ? 'active' : ''}`}
onClick={() => setActiveTab(tab.id)}
>
{tab.label}
</button>
))}
</div>
{/* Tab Content */}
<div className="tab-content">
{activeTab === 'overview' && <OverviewContent />}
{activeTab === 'details' && <DetailsContent />}
{activeTab === 'reviews' && <ReviewsContent />}
</div>
</div>
);
}
Advanced Patterns
Route Protection
Implement route protection and authentication guards
import { Navigate, useLocation } from "react-router";
import { useAuth } from "./hooks/useAuth";
function ProtectedRoute({ children }) {
const { user } = useAuth();
const location = useLocation();
if (!user) {
// Redirect to login with return URL
return (
<Navigate
to="/login"
state={{ from: location }}
replace
/>
);
}
return children;
}
// Usage in routes
function App() {
return (
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/public" element={<PublicPage />} />
{/* Protected routes */}
<Route
path="/dashboard"
element={
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
}
/>
{/* Or using layout route */}
<Route element={<ProtectedRoute />}>
<Route path="/profile" element={<Profile />} />
<Route path="/settings" element={<Settings />} />
</Route>
</Routes>
);
}
Conditional Redirects
Implement conditional redirects based on application state
import { Navigate } from "react-router";
function Dashboard() {
const { user, loading } = useAuth();
if (loading) {
return <LoadingSpinner />;
}
// Redirect based on user role
if (user?.role === 'admin') {
return <Navigate to="/admin-dashboard" replace />;
}
if (user?.role === 'manager') {
return <Navigate to="/manager-dashboard" replace />;
}
return <UserDashboard />;
}
// Conditional redirect in routes
function App() {
return (
<Routes>
<Route
path="/dashboard"
element={
user?.isFirstLogin ?
<Navigate to="/onboarding" /> :
<Dashboard />
}
/>
</Routes>
);
}
Error Boundaries and 404 Routes
Handle 404 errors and implement catch-all routes
import { Routes, Route } from "react-router";
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
{/* Nested routes with error handling */}
<Route path="/products" element={<ProductsLayout />}>
<Route index element={<ProductsList />} />
<Route path=":id" element={<ProductDetail />} />
{/* Catch-all for products section */}
<Route path="*" element={<ProductNotFound />} />
</Route>
{/* Global 404 route - must be last */}
<Route path="*" element={<NotFound />} />
</Routes>
);
}
// Custom 404 component
function NotFound() {
const location = useLocation();
return (
<div>
<h1>Page Not Found</h1>
<p>The page `{location.pathname}` does not exist.</p>
<Link to="/">Go Home</Link>
</div>
);
}
URL State Management
Manage complex application state through URL parameters
import { useSearchParams, useNavigate } from "react-router";
function ProductList() {
const [searchParams, setSearchParams] = useSearchParams();
const navigate = useNavigate();
// Parse complex state from URL
const filters = {
category: searchParams.get('category') || 'all',
minPrice: parseInt(searchParams.get('minPrice') || '0'),
maxPrice: parseInt(searchParams.get('maxPrice') || '1000'),
tags: searchParams.get('tags')?.split(',') || [],
sortBy: searchParams.get('sortBy') || 'name',
page: parseInt(searchParams.get('page') || '1'),
};
// Update URL state
const updateFilters = (newFilters) => {
const params = new URLSearchParams();
Object.entries({ ...filters, ...newFilters }).forEach(([key, value]) => {
if (value !== null && value !== undefined && value !== '') {
if (Array.isArray(value)) {
if (value.length > 0) {
params.set(key, value.join(','));
}
} else {
params.set(key, value.toString());
}
}
});
setSearchParams(params);
};
// Reset all filters
const clearFilters = () => {
navigate(location.pathname, { replace: true });
};
return (
<div>
<FilterPanel
filters={filters}
onFiltersChange={updateFilters}
onClearFilters={clearFilters}
/>
<ProductGrid filters={filters} />
</div>
);
}
Best Practices
Lazy Loading Routes
Implement code splitting and lazy loading for better performance
import { lazy, Suspense } from "react";
import { Routes, Route } from "react-router";
// Lazy load components
const Dashboard = lazy(() => import("./components/Dashboard"));
const Settings = lazy(() => import("./components/Settings"));
const Profile = lazy(() => import("./components/Profile"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Suspense>
);
}
// Or create a wrapper component
function LazyRoute({ children }) {
return (
<Suspense fallback={<LoadingSpinner />}>
{children}
</Suspense>
);
}
Custom Hooks for Router Logic
Create reusable custom hooks for common routing patterns
import { useLocation, useNavigate } from "react-router";
// Custom hook for breadcrumbs
export function useBreadcrumbs() {
const location = useLocation();
const pathSegments = location.pathname
.split('/')
.filter(Boolean)
.map((segment, index, array) => ({
name: segment.charAt(0).toUpperCase() + segment.slice(1),
path: '/' + array.slice(0, index + 1).join('/'),
}));
return [{ name: 'Home', path: '/' }, ...pathSegments];
}
// Custom hook for navigation with confirmation
export function useNavigateWithConfirmation() {
const navigate = useNavigate();
return (to, options = {}) => {
const shouldNavigate = options.skipConfirmation ||
window.confirm('Are you sure you want to leave this page?');
if (shouldNavigate) {
navigate(to, options);
}
};
}
// Custom hook for query string management
export function useQueryParams() {
const [searchParams, setSearchParams] = useSearchParams();
const setParam = (key, value) => {
const params = new URLSearchParams(searchParams);
params.set(key, value);
setSearchParams(params);
};
const removeParam = (key) => {
const params = new URLSearchParams(searchParams);
params.delete(key);
setSearchParams(params);
};
const getParam = (key, defaultValue = null) => {
return searchParams.get(key) || defaultValue;
};
return { setParam, removeParam, getParam, searchParams };
}
Route-based Code Organization
Organize routes and components in a scalable file structure
// File structure
src/
routes/
index.tsx // Route definitions
guards/
ProtectedRoute.tsx
AdminRoute.tsx
layouts/
AppLayout.tsx
AuthLayout.tsx
pages/
Home/
index.tsx
components/
hooks/
Dashboard/
index.tsx
components/
hooks/
// routes/index.tsx
import { createBrowserRouter } from "react-router";
import AppLayout from "./layouts/AppLayout";
import ProtectedRoute from "./guards/ProtectedRoute";
import { lazy } from "react";
const Home = lazy(() => import("./pages/Home"));
const Dashboard = lazy(() => import("./pages/Dashboard"));
const Profile = lazy(() => import("./pages/Profile"));
export const router = createBrowserRouter([
{
path: "/",
element: <AppLayout />,
children: [
{
index: true,
element: <Home />
},
{
path: "dashboard",
element: (
<ProtectedRoute>
<Dashboard />
</ProtectedRoute>
)
},
{
path: "profile",
element: (
<ProtectedRoute>
<Profile />
</ProtectedRoute>
)
}
]
}
]);
React Router - Interactive Developer Reference
Hover over code blocks to copy or run in live playground