What is React Router?
React Router is a collection of navigational components that compose declaratively with your application. Whether you're building a simple blog or a complex enterprise application, React Router enables you to create dynamic, client-side routing that feels natural and performs excellently.
Key benefits include:
- Client-side navigation: Instant page transitions without full browser refreshes
- Deep linking: Shareable URLs that point to specific application states
- History management: Proper browser history navigation with back/forward buttons
- Nested layouts: Hierarchical routing patterns that mirror your UI structure
- Data integration: Built-in patterns for loading data alongside routes
React Router v6 represents the standard for building single-page applications with React, enabling seamless navigation while maintaining browser history, deep linking, and proper SEO considerations. As the de facto routing library for React, it powers everything from simple content sites to complex web applications requiring sophisticated navigation patterns. To build truly scalable interfaces, consider combining React Router with systematic approaches like Atomic Design methodology for component organization. React Router Official Documentation
Getting Started with React Router V6
Installation and Setup
React Router v6 uses a modular package structure for flexible integration:
npm install react-router-dom
# For React Native:
npm install react-router-native
The core package exports all routing functionality:
import {
BrowserRouter,
Routes,
Route,
Link,
useParams,
useNavigate
} from 'react-router-dom';
Configuration starts with wrapping your application in a router component. The installation process is straightforward, and with proper React application architecture, you can have routing set up in minutes. For teams working with TypeScript, leveraging type-safe configurations helps prevent runtime routing errors. React Router v6.30.2 Official Tutorial
React Router provides several router implementations for different scenarios
BrowserRouter
The most common choice for standard web applications. Uses the HTML5 History API for clean URLs without hash fragments.
HashRouter
Useful when hosting on servers that don't support client-side routing or when URL structure constraints exist.
MemoryRouter
Ideal for testing environments, mobile apps, or scenarios where browser history shouldn't persist.
StaticRouter
Used for server-side rendering to handle incoming requests without a browser.
1import { BrowserRouter, Routes, Route } from 'react-router-dom';2import Home from './pages/Home';3import About from './pages/About';4 5function App() {6 return (7 <BrowserRouter>8 <Routes>9 <Route path="/" element={<Home />} />10 <Route path="/about" element={<About />} />11 </Routes>12 </BrowserRouter>13 );14}Core Routing Components
The Routes Component
The Routes component serves as the top-level container for route definitions. It examines the current URL and renders the first matching Route within its children. This pattern replaces the older Switch component from React Router v5.
Key behaviors:
- Routes are matched in order from top to bottom
- The first matching route wins (exclusive matching)
- Use
pathprop withelementfor component rendering - Empty path or wildcard
*catches unmatched URLs
The Route Component
The Route component defines a single routing rule. Each route specifies a path pattern and the element (React component) to render when that path matches. Route matching follows these principles: paths are matched exactly by default in v6 (unlike partial matching in v5), and route order matters - more specific routes should come first.
Understanding these core components is essential for building robust React applications with proper navigation architecture. When building reusable components that need to interact with routing, techniques like React refs can help manage DOM interactions within route components.
| Pattern | Example | Matches |
|---|---|---|
| Exact string | /about | Only /about |
| Dynamic segment | /users/:id | /users/123, /users/456 |
| Optional segment | /products/:category? | /products, /products/electronics |
| Wildcard | /docs/* | /docs, /docs/getting-started |
| Multiple segments | /events/:year/:month | /events/2025/01 |
Navigation with Link and NavLink
The Link component provides declarative navigation for single-page applications. Instead of using anchor tags that trigger full page reloads, Link performs client-side navigation while updating the browser history. This approach is fundamental to creating the smooth, app-like experience users expect from modern web applications.
NavLink extends Link with automatic active state detection, making it ideal for navigation menus where you want visual feedback for the current page. The active class or style is applied automatically when the route matches.
Programmatic Navigation with useNavigate
The useNavigate hook provides imperative navigation for scenarios where you need to navigate based on user actions, form submissions, or other runtime conditions. This is essential for handling authentication flows, form submissions, and conditional redirects. When building accessible navigation components, consider leveraging headless UI libraries like Radix UI for unstyled, accessible primitives.
1import { Link, NavLink, useNavigate } from 'react-router-dom';2 3function NavigationExample() {4 const navigate = useNavigate();5 6 // Basic navigation with Link7 return (8 <nav>9 <Link to="/products">Products</Link>10 <Link to="/products/123">View Product</Link>11 </nav>12 );13}14 15// NavLink with active styling16function NavLinkExample() {17 return (18 <NavLink19 to="/dashboard"20 className={({ isActive }) => isActive ? 'active' : ''}21 >22 Dashboard23 </NavLink>24 );25}26 27// Programmatic navigation28function LoginForm() {29 const navigate = useNavigate();30 31 const handleSubmit = async (event) => {32 event.preventDefault();33 const success = await submitCredentials();34 35 if (success) {36 navigate('/dashboard', { replace: true });37 }38 };39 40 return <form onSubmit={handleSubmit}>{/* form fields */}</form>;41}Dynamic Routes and Parameters
Defining Dynamic Routes
Dynamic routes use path parameters to capture variable parts of URLs. Parameters are defined with a colon prefix and can capture any value that appears in that position. This pattern is essential for building flexible web applications that handle dynamic content like products, users, and posts.
Accessing Parameters with useParams
The useParams hook returns an object of key-value pairs for dynamic route parameters. This enables components to read values directly from the URL and use them for data fetching or display.
Query Parameters with useSearchParams
Query parameters (everything after ? in the URL) are accessed through useSearchParams. This hook provides a similar interface to React state for reading and updating URL parameters, making it easy to implement filtering, sorting, and pagination.
1import { useParams, useSearchParams } from 'react-router-dom';2 3// Dynamic route parameters4<Routes>5 <Route path="/products/:productId" element={<ProductDetail />} />6 <Route path="/stores/:storeId/products/:productId" element={<StoreProduct />} />7 <Route path="/users/:userId/:tab?" element={<UserProfile />} />8</Routes>9 10// Accessing URL parameters11function ProductDetail() {12 const { productId } = useParams();13 return <div>Product: {productId}</div>;14}15 16// Query parameters17function ProductList() {18 const [searchParams, setSearchParams] = useSearchParams();19 const category = searchParams.get('category');20 const page = parseInt(searchParams.get('page') || '1');21 22 return (23 <div>24 <p>Category: {category}</p>25 <p>Page: {page}</p>26 </div>27 );28}Nested Routes and Layouts
Understanding Nested Routes
Nested routes mirror the hierarchical structure of your UI. When a parent route renders an Outlet, child routes render within that context, creating a natural layout pattern. This approach is particularly powerful for building dashboard-style applications with consistent navigation across multiple sections.
The Outlet Component
The Outlet component serves as a placeholder where child routes should render. This enables layouts that wrap child content while maintaining proper routing. Parent routes can also pass context to child routes through the outlet, enabling sophisticated data sharing patterns.
Layout routes exist purely to provide structure without adding their own path segment. They wrap child routes and often contain persistent UI elements like sidebars, headers, and navigation menus that remain visible while the content area updates.
1import { Outlet, Link } from 'react-router-dom';2 3function DashboardLayout() {4 return (5 <div className="dashboard">6 <nav className="sidebar">7 <Link to="/dashboard">Overview</Link>8 <Link to="/dashboard/analytics">Analytics</Link>9 <Link to="/dashboard/settings">Settings</Link>10 </nav>11 12 <main className="content">13 {/* Child routes render here */}14 <Outlet />15 </main>16 </div>17 );18}19 20// Nested route definitions21<Route path="/dashboard" element={<DashboardLayout />}>22 <Route index element={<DashboardOverview />} />23 <Route path="analytics" element={<Analytics />} />24 <Route path="settings" element={<Settings />} />25</Route>Route Hooks and Utilities
useNavigate: Programmatic Navigation
Beyond basic navigation, useNavigate supports sophisticated routing scenarios including state passing, history manipulation, and conditional redirects. This hook is essential for handling authentication flows and form submissions in production React applications.
useLocation: Current URL Information
The useLocation hook returns the current location object, useful for tracking navigation patterns, analytics, or conditionally rendering based on URL. The location object includes pathname, search, hash, and any state passed during navigation.
useRouteError: Error Handling
When a route or its loader/action throws an error, useRouteError provides access to the error for custom handling. This enables graceful error pages, logging, and recovery strategies that maintain a positive user experience even when things go wrong.
useNavigate
Imperative navigation for programmatic routing, form submissions, and conditional redirects
useLocation
Access current URL information including pathname, search, hash, and navigation state
useParams
Extract dynamic route parameters from the current URL
useSearchParams
Read and update URL query parameters with a React state-like interface
useRouteError
Catch and handle route errors for custom error pages and graceful degradation
useOutletContext
Pass data from parent routes to nested child components through outlets
Advanced Routing Patterns
Protected Routes and Authentication
Create protected routes that redirect unauthenticated users and enforce role-based access control. This pattern is crucial for building secure web applications with user authentication and authorization.
Route-Based Code Splitting
Use React.lazy with Suspense for route-based code splitting to improve initial load time and reduce bundle sizes. This optimization technique loads route components only when needed, resulting in faster initial page loads and better user experience.
Custom Route Matching
For advanced routing scenarios, use the matchPath utility for complex pattern matching, regex support, and custom route resolution strategies. This enables sophisticated routing logic beyond standard path patterns.
1import { Navigate, Outlet } from 'react-router-dom';2import { useAuth } from './auth';3 4function ProtectedRoute({ allowedRoles }) {5 const { user, isAuthenticated } = useAuth();6 7 if (!isAuthenticated) {8 return <Navigate to="/login" replace />;9 }10 11 if (allowedRoles && !allowedRoles.includes(user.role)) {12 return <Navigate to="/unauthorized" replace />;13 }14 15 return <Outlet />;16}17 18// Route configuration with protection19<Route element={<ProtectedRoute allowedRoles={['admin', 'editor']} />}>20 <Route path="/admin" element={<AdminDashboard />} />21 <Route path="/admin/users" element={<UserManagement />} />22</Route>Testing Routes
Testing with MemoryRouter
Test routes without browser dependencies using MemoryRouter. This enables isolated unit testing of routing logic, ensuring your navigation works correctly before deploying to production. MemoryRouter stores navigation state in memory rather than the browser URL, making it ideal for test environments.
Testing Links and Navigation
Verify link behavior and assert URL changes in your tests. Testing routing logic is an essential part of maintaining reliable React applications, catching navigation issues before they affect users. When building comprehensive test suites for React applications, combining routing tests with component-level ref testing using React refs ensures thorough coverage. Trio.dev Complete Guide to React Router v6
1import { render, screen } from '@testing-library/react';2import { MemoryRouter } from 'react-router-dom';3import App from './App';4 5test('renders home page at root path', () => {6 render(7 <MemoryRouter initialEntries={['/']}>8 <App />9 </MemoryRouter>10 );11 12 expect(screen.getByText('Welcome')).toBeInTheDocument();13});14 15test('navigates to about page', () => {16 render(17 <MemoryRouter initialEntries={['/']}>18 <App />19 </MemoryRouter>20 );21 22 fireEvent.click(screen.getByText('About'));23 expect(screen.getByText('About Us')).toBeInTheDocument();24});Performance Optimization
Route-Based Lazy Loading
Organize routes to enable optimal code splitting using React.lazy and Suspense. This approach reduces initial bundle size by loading route components only when users navigate to them. For complex React applications, this can significantly improve Time to Interactive (TTI) metrics.
Prefetching Resources
Use Link's prefetch prop for preloading resources when users hover over links. This intelligent prefetching strategy loads route components before users click, resulting in near-instant navigation experiences. Prefetch options include render for viewport-based loading and intent for hover/focus-based loading.
1import { Suspense, lazy } from 'react';2import { Routes, Route } from 'react-router-dom';3 4const Home = lazy(() => import('./pages/Home'));5const About = lazy(() => import('./pages/About'));6const Products = lazy(() => import('./pages/Products'));7 8function App() {9 return (10 <Suspense fallback={<LoadingSpinner />}>11 <Routes>12 <Route path="/" element={<Home />} />13 <Route path="/about" element={<About />} />14 <Route path="/products" element={<Products />} />15 </Routes>16 </Suspense>17 );18}19 20// Prefetch on render21<Link to="/products/123" prefetch="render">22 View Product23</Link>Common Patterns and Best Practices
Organizing Route Definitions
Create a dedicated routes configuration for maintainable, centralized route management. A well-organized route structure is essential for scaling React applications and keeping routing logic manageable as your application grows.
Type-Safe Routes with TypeScript
Leverage TypeScript for type-safe route configurations and inferred types. TypeScript provides compile-time checking for route parameters, preventing runtime errors and improving developer experience with autocomplete support.
Error Boundary Strategy
Implement reusable error boundaries for graceful degradation across routes. Error boundaries catch JavaScript errors in child components and display fallback UI, ensuring a single error doesn't break the entire application.
Migration from React Router v5
Breaking Changes from v5 to v6
React Router v6 introduced several significant changes that improve code quality and reduce bugs:
| v5 Pattern | v6 Pattern |
|---|---|
Switch | Routes |
component={Home} | element={<Home />} |
render={() => <Home />} | element={<Home />} |
useHistory | useNavigate |
| Partial path matching | Exact matching by default |
Redirect | Navigate |
Compatibility Layer
For gradual migrations, React Router provides compatibility utilities to convert v5-style routes to v6. The createRoutesFromChildren function allows you to define routes in a JSX format similar to v5 while using v6's improved matching algorithm.
For teams maintaining legacy React applications, a phased migration approach allows incremental adoption of v6 features without risking breaking changes. When modernizing older React codebases, combining routing upgrades with systematic component refactoring using Atomic Design principles creates more maintainable architectures. ShareTech React Router 2025 Guide
1// v5 style (old)2<Switch>3 <Route exact path="/" component={Home} />4 <Route path="/about" render={() => <About />} />5 <Redirect from="/old" to="/new" />6</Switch>7 8// v6 style (new)9<Routes>10 <Route path="/" element={<Home />} />11 <Route path="/about" element={<About />} />12 <Route path="/old" element={<Navigate to="/new" replace />} />13</Routes>Frequently Asked Questions
Conclusion
React Router v6 provides a comprehensive solution for client-side routing in React applications. From basic navigation to complex nested layouts and data integration, the library offers patterns for every routing scenario.
Key takeaways:
- Start with BrowserRouter for standard web applications
- Use Routes and Route for defining route structure
- Leverage Link and NavLink for navigation, useNavigate for programmatic routing
- Embrace nested routes and Outlets for hierarchical layouts
- Implement protected routes for authentication flows
- Apply code splitting for performance optimization
Mastering React Router v6 is essential for building professional React applications that deliver excellent user experiences. The library's thoughtful API design and robust feature set make it the definitive choice for client-side routing in the React ecosystem.
Continue exploring:
For teams looking to build sophisticated single-page applications, understanding React Router v6 patterns is just one piece of the puzzle. Consider combining routing expertise with accessible component libraries like Radix UI and structured design systems using Atomic Design methodology. Consider exploring our full-stack development services to build complete, production-ready applications with proper architecture, state management, and performance optimization.
Sources
- React Router v6.30.2 Official Tutorial - Comprehensive official documentation covering setup, routing concepts, data loading, mutations, forms, and advanced patterns
- React Router Official Documentation - Primary reference for all React Router v6 APIs, components, hooks, and patterns
- Trio.dev Complete Guide to React Router v6 - Step-by-step tutorial covering installation, configuration, route parameters, nested routes, and protected routes
- ShareTech React Router 2025 Guide - Beginner-friendly guide explaining routing fundamentals and practical examples