Back to Blog
Lesson 17 of the Intermediate React: Hooks, State & Data Patterns course
ReactJune 26, 20263 min read

Dynamic Routing with URL Parameters in React Router

Master dynamic routing with React Router. Learn how to define parameterized paths and use the useParams hook to display unique data in your dashboard.

ReactReact Routerdynamic routingURL parametersnavigationweb developmentjavascriptfrontend

Previously in this course, we laid the foundation for multi-page applications by exploring the Introduction to React Router: Building Multi-Page SPAs. While static routes are great for pages like "About" or "Settings," real-world dashboards require flexible content, such as viewing specific user profiles or project details. In this lesson, we move beyond hardcoded links to implement dynamic routing, allowing our application to react to changing URL parameters.

Understanding Parameterized Paths

In a standard application, you don't create a separate route for every single item in your database. Instead, you define a pattern. A parameterized path is a route string that contains a variable segment, denoted by a colon (:).

When you define a route like /projects/:projectId, the React Router engine treats :projectId as a placeholder. When a user navigates to /projects/123, the router matches the path and extracts 123 as the value for the projectId key. This allows a single component to handle any number of individual project pages.

Extracting Data with useParams

To access these segments inside your component, React Router provides the useParams hook. This hook returns an object where the keys are the names you defined in your route path, and the values are the strings found in the current URL.

Worked Example: Building a Project Detail View

Let’s advance our dashboard project. We have a list of projects, and we want to click on one to see its specific details.

First, define the dynamic route in your main router configuration:

JSX
import { BrowserRouter, Routes, Route } from CE9178">'react-router-dom';
import ProjectDashboard from CE9178">'./ProjectDashboard';
import ProjectDetails from CE9178">'./ProjectDetails';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/projects" element={<ProjectDashboard />} />
        {/* The :id segment is the dynamic part */}
        <Route path="/projects/:id" element={<ProjectDetails />} />
      </Routes>
    </BrowserRouter>
  );
}

Now, implement the ProjectDetails component to consume that parameter:

JSX
import { useParams } from CE9178">'react-router-dom';

function ProjectDetails() {
  // useParams extracts the CE9178">'id' from the URL
  const { id } = useParams();

  // In a real app, you'd use this ID to fetch data
  return (
    <div>
      <h1>Project Details</h1>
      <p>Displaying data for project ID: {id}</p>
    </div>
  );
}

Hands-on Exercise

  1. Open your current dashboard project.
  2. Locate your existing project list component.
  3. Update your Link components (or <a> tags if you haven't switched yet) to point to /projects/:id, replacing :id with the actual project ID from your data source.
  4. Create a new ProjectDetails component, add it to your Routes configuration, and use useParams to display the ID on the screen when a user clicks a project.

Common Pitfalls

  • Forgetting the Colon: A common mistake is defining a route as /projects/id instead of /projects/:id. Without the colon, React Router looks for a literal path segment named "id" rather than a variable.
  • Stale Data: When a user navigates from /projects/1 to /projects/2, the component does not unmount; it simply re-renders with new props from useParams. If you are fetching data inside useEffect, ensure id is included in your dependency array so the fetch triggers on every URL change.
  • Type Coercion: Parameters from the URL are always returned as strings. If your database IDs are numbers, remember to convert them (e.g., parseInt(id)) before performing comparisons or lookups in your state.

Recap

Dynamic routing is the backbone of any data-driven application. By defining paths with segments like :id and leveraging the useParams hook, you can create a single, reusable component that serves thousands of unique data points. This approach keeps your code DRY and your routing configuration clean, providing a seamless navigation experience as we continue building our dashboard.

Up next: We will explore Nested Routes and Layouts to maintain consistent UI structures across your application.

Similar Posts