React Router Parameters
Introduction
In web applications, it's common to need dynamic routes where parts of the URL change based on what content we want to display. For example, in an e-commerce site, you might have product pages with URLs like /products/1
, /products/2
, etc. Instead of creating a separate route for each product, React Router allows us to define route parameters that can capture these varying parts of the URL.
Route parameters (sometimes called URL parameters) are dynamic segments of a URL that can change while still matching a single route pattern. This feature is essential for creating dynamic, data-driven applications that respond to user navigation.
Understanding Route Parameters
Route parameters are defined in your route paths with a colon (:
) followed by the parameter name. This tells React Router to match any value at that position in the URL and make it available to your components.
Basic Syntax
<Route path="/products/:productId" element={<ProductDetail />} />
In this example, :productId
is a route parameter. When a user navigates to /products/1
, the ProductDetail
component will render and have access to productId
with a value of 1
.
Setting Up Route Parameters
Let's walk through setting up routes with parameters in a React application:
- First, make sure you have React Router installed:
npm install react-router-dom
- Create a basic application structure:
// App.jsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './Home';
import ProductList from './ProductList';
import ProductDetail from './ProductDetail';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<ProductList />} />
<Route path="/products/:productId" element={<ProductDetail />} />
</Routes>
</BrowserRouter>
);
}
export default App;
In this setup, we have a static route for the product list page and a dynamic route for individual product details.
Accessing Route Parameters
React Router provides the useParams
hook to access route parameters in your components.
// ProductDetail.jsx
import { useParams } from 'react-router-dom';
function ProductDetail() {
const { productId } = useParams();
return (
<div>
<h1>Product Details</h1>
<p>You are viewing product with ID: {productId}</p>
</div>
);
}
export default ProductDetail;
When a user visits /products/42
, the ProductDetail
component will display:
Product Details
You are viewing product with ID: 42
Practical Example: Building a Product Catalog
Let's create a more complete example of a product catalog to demonstrate how parameters work in a real application:
// ProductList.jsx
import { Link } from 'react-router-dom';
function ProductList() {
const products = [
{ id: 1, name: 'Laptop', price: 999 },
{ id: 2, name: 'Phone', price: 699 },
{ id: 3, name: 'Tablet', price: 499 },
{ id: 4, name: 'Smartwatch', price: 299 },
];
return (
<div>
<h1>Our Products</h1>
<ul>
{products.map(product => (
<li key={product.id}>
<Link to={`/products/${product.id}`}>
{product.name} - ${product.price}
</Link>
</li>
))}
</ul>
</div>
);
}
export default ProductList;
// ProductDetail.jsx
import { useParams, Link } from 'react-router-dom';
import { useState, useEffect } from 'react';
function ProductDetail() {
const { productId } = useParams();
const [product, setProduct] = useState(null);
const [loading, setLoading] = useState(true);
// Simulate fetching product data
useEffect(() => {
// In a real application, you would fetch data from an API
const fetchProduct = async () => {
// Simulated API call with timeout
setTimeout(() => {
// Mock product data
const productData = {
1: { id: 1, name: 'Laptop', price: 999, description: 'Powerful laptop with the latest processor' },
2: { id: 2, name: 'Phone', price: 699, description: 'Feature-rich smartphone with excellent camera' },
3: { id: 3, name: 'Tablet', price: 499, description: 'Lightweight tablet perfect for entertainment' },
4: { id: 4, name: 'Smartwatch', price: 299, description: 'Track your fitness and stay connected' },
}[productId];
setProduct(productData);
setLoading(false);
}, 500);
};
fetchProduct();
}, [productId]);
if (loading) {
return <div>Loading product information...</div>;
}
if (!product) {
return <div>Product not found</div>;
}
return (
<div>
<h1>{product.name}</h1>
<p><strong>Price:</strong> ${product.price}</p>
<p><strong>Description:</strong> {product.description}</p>
<p><strong>Product ID:</strong> {productId}</p>
<Link to="/products">Back to Products</Link>
</div>
);
}
export default ProductDetail;
In this example:
ProductList
displays a list of products with links to their detail pagesProductDetail
extracts theproductId
parameter and uses it to fetch and display product information- The
useEffect
hook depends onproductId
, so it re-runs whenever the parameter changes
Multiple Route Parameters
React Router allows you to define multiple parameters in a single route path:
<Route path="/category/:categoryId/product/:productId" element={<CategoryProduct />} />
You can access both parameters using the useParams
hook:
// CategoryProduct.jsx
import { useParams } from 'react-router-dom';
function CategoryProduct() {
const { categoryId, productId } = useParams();
return (
<div>
<h1>Product Details</h1>
<p>Category ID: {categoryId}</p>
<p>Product ID: {productId}</p>
</div>
);
}
When a user navigates to /category/electronics/product/42
, they will see:
Product Details
Category ID: electronics
Product ID: 42
Optional Parameters
Sometimes you might want certain parameters to be optional. React Router v6 handles this through nested routes:
// App.jsx
<Routes>
<Route path="/users" element={<UserLayout />}>
<Route index element={<UserList />} />
<Route path=":userId" element={<UserDetail />} />
</Route>
</Routes>
// UserLayout.jsx
import { Outlet } from 'react-router-dom';
function UserLayout() {
return (
<div>
<h1>User Management</h1>
<Outlet />
</div>
);
}
In this structure:
/users
will render theUserLayout
withUserList
(index route)/users/123
will render theUserLayout
withUserDetail
and access to theuserId
parameter
Parameter Constraints with Regular Expressions
React Router v6 doesn't directly support regex constraints in routes like v5 did. However, you can handle validation inside your component:
import { useParams, Navigate } from 'react-router-dom';
function ProductDetail() {
const { productId } = useParams();
// Validate that productId is a number
if (!/^\d+$/.test(productId)) {
return <Navigate to="/not-found" replace />;
}
// Continue with valid productId
return (
<div>
<h1>Product Details</h1>
<p>You are viewing product with ID: {productId}</p>
</div>
);
}
Common Use Cases for Route Parameters
Route parameters are incredibly versatile and are commonly used for:
- Resource Identification: Such as
/users/:userId
,/products/:productId
- Filtering and Searching: Like
/search/:query
,/category/:category
- Localization: For example,
/blog/:language/:slug
- Pagination: Such as
/products/page/:pageNumber
- Versioning: Like
/api/:version/endpoint
Data Flow with Parameters
Here's a visualization of how data flows when using route parameters:
Summary
Route parameters in React Router provide a powerful way to create dynamic, data-driven applications. They allow you to:
- Define dynamic segments in your route paths
- Extract parameter values using the
useParams
hook - Create flexible routing patterns for your application
- Build intuitive navigation with semantic URLs
By leveraging route parameters, you can create more maintainable and user-friendly React applications that respond dynamically to user navigation.
Additional Exercises
- Create a blog application with routes for viewing posts by category:
/blog/:category
- Build a user management system with nested routes:
/users/:userId/settings/:settingType
- Implement a product search with optional parameters:
/search/:query?/category/:categoryId?
- Create a multi-step form with the current step in the URL:
/form/step/:stepNumber
Further Resources
Happy routing!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)