Understanding React Router's Purpose
Imagine you're designing a city's transportation system. Just as a city needs clear routes and navigation to help people reach their destinations, a React application needs a routing system to help users navigate between different views and components. React Router serves as this navigation system, managing what content users see based on the URL they visit.
Let's start by understanding how to set up basic routing in a React application:
// First, import necessary components from react-router-dom
import {
BrowserRouter,
Routes,
Route
} from 'react-router-dom';
// Create components for different routes
function Home() {
return <h1>Welcome to our App!</h1>;
}
function About() {
return <h1>About Us</h1>;
}
function Contact() {
return <h1>Contact Us</h1>;
}
// Set up the routing structure
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</BrowserRouter>
);
}
Creating Layouts with Nested Routes
Just as a city might have different districts with their own layouts but sharing common elements like main roads, React Router allows you to create layouts that share common elements across multiple routes. This is achieved using the Outlet component:
import { Outlet } from 'react-router-dom';
// Create a layout component that will wrap other routes
function MainLayout() {
return (
<div className="app-layout">
<header>
<nav>
{/* Navigation links will go here */}
</nav>
</header>
{/* Outlet renders the child route's element */}
<main>
<Outlet />
</main>
<footer>
<p>© 2025 Our App</p>
</footer>
</div>
);
}
// Set up nested routes using the layout
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<MainLayout />}>
<Route index element={<Home />} />
<Route path="about" element={<About />} />
<Route path="contact" element={<Contact />} />
</Route>
</Routes>
</BrowserRouter>
);
}
Working with Dynamic Routes and Parameters
Often, you'll need routes that can handle dynamic values, like user IDs or product names. The useParams hook helps you access these values:
import { useParams } from 'react-router-dom';
// Component to display user profiles
function UserProfile() {
// Extract userId from the URL
const { userId } = useParams();
return (
<div className="user-profile">
<h1>User Profile: {userId}</h1>
{/* Add profile content here */}
</div>
);
}
// Product details component with multiple parameters
function ProductDetails() {
const { category, productId } = useParams();
return (
<div className="product-details">
<h1>{category} Product: {productId}</h1>
{/* Add product details here */}
</div>
);
}
// Set up routes with parameters
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<MainLayout />}>
<Route path="users/:userId" element={<UserProfile />} />
<Route
path="products/:category/:productId"
element={<ProductDetails />}
/>
</Route>
</Routes>
</BrowserRouter>
);
}
Putting It All Together: Building a Complete Router Setup
Let's create a complete example that demonstrates all these concepts working together:
import {
BrowserRouter,
Routes,
Route,
Link,
NavLink,
Outlet,
useParams,
useNavigate
} from 'react-router-dom';
// Layout component with navigation
function Layout() {
return (
<div className="app">
<header>
<nav>
<NavLink
to="/"
end
className={({ isActive }) =>
`nav-link ${isActive ? 'active' : ''}`
}
>
Home
</NavLink>
<NavLink
to="/products"
className={({ isActive }) =>
`nav-link ${isActive ? 'active' : ''}`
}
>
Products
</NavLink>
</nav>
</header>
<main>
<Outlet />
</main>
</div>
);
}
// Products list with navigation
function ProductsList() {
const navigate = useNavigate();
const handleProductClick = (productId) => {
navigate(`/products/${productId}`);
};
return (
<div className="products">
<h1>Our Products</h1>
{products.map(product => (
<div
key={product.id}
onClick={() => handleProductClick(product.id)}
className="product-card"
>
<h2>{product.name}</h2>
<p>{product.description}</p>
</div>
))}
</div>
);
}
// Product detail page with parameters
function ProductDetail() {
const { productId } = useParams();
const navigate = useNavigate();
// Simulate loading product data
const product = findProduct(productId);
if (!product) {
return <Navigate to="/products" replace />;
}
return (
<div className="product-detail">
<h1>{product.name}</h1>
<p>{product.description}</p>
<button onClick={() => navigate(-1)}>
Back to Products
</button>
</div>
);
}
// Complete router setup
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route index element={<Home />} />
<Route path="products" element={<ProductsList />} />
<Route
path="products/:productId"
element={<ProductDetail />}
/>
<Route path="*" element={<NotFound />} />
</Route>
</Routes>
</BrowserRouter>
);
}