React Route Parameters

In the last lesson, React Creating Routes, you mapped fixed paths like /about to components. This lesson covers route parameters, so one route can handle many URLs like /users/1 and /users/2.

🤔 Why do we need route parameters?

Some pages follow the same pattern but the data differs each time.

  • A user profile page is the same layout, but /users/1 and /users/2 show different people.
  • A product page like /products/42 changes per product.
  • You can’t write one Route per user, there could be thousands.
  • So you need one route that matches any user id and passes it to the page.

🧩 Define a dynamic path with a colon

You mark the changing part of a path with a colon (:). That tells React Router “this part is a parameter, match anything here”.

import { Routes, Route } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/users/:id" element={<UserProfile />} />
</Routes>
);
}

Read the path carefully.

  • /users/:id has a fixed part, /users/, and a parameter, :id.
  • The :id matches whatever comes after /users/, like 1, 42, or abc.
  • So this one route matches /users/1, /users/2, and so on, all with the same component.
  • The name after the colon, id, is what you’ll use to read the value.

The name is up to you

:id is just a name you chose. You could write :userId or :slug. Whatever you name it in the path is the name you’ll read it by in the component.

🔑 Read the value with useParams

The route matched, but how does the component know which id was in the URL? You read it with the useParams hook.

import { useParams } from "react-router-dom";
function UserProfile() {
const { id } = useParams(); // read the :id from the URL
return <h1>Profile of user {id}</h1>;
}

Walk through what useParams gives you.

  • useParams() returns an object of all the parameters in the current URL.
  • The key names match what you wrote in the path, so the path :id gives you an id.
  • So const { id } = useParams() pulls the id out, ready to use.
  • Visit /users/5 and id is "5"; visit /users/9 and id is "9".

Output

(visit /users/5 ) -> Profile of user 5
(visit /users/9 ) -> Profile of user 9

🖥️ Using the parameter to fetch data

The real power shows when you use the id to load that item’s data, combining what you learned about fetching.

import { useParams } from "react-router-dom";
import { useState, useEffect } from "react";
function UserProfile() {
const { id } = useParams();
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
.then((res) => res.json())
.then((data) => setUser(data));
}, [id]); // refetch when the id in the URL changes
if (!user) return <p>Loading...</p>;
return <h1>{user.name}</h1>;
}

See how the pieces connect.

  • useParams gives the id from the URL, like 5.
  • We put that id straight into the fetch URL, so we load that exact user.
  • id is in the dependency array, so visiting a different user’s URL refetches the right data.
  • So one component handles every user, just by reading the id and fetching. This read-the-id, load-the-item, show-it pattern is how every detail page works.

⚠️ The value is always a string

One thing to watch. Whatever useParams gives you is a string, even if the URL looks like a number.

const { id } = useParams();
console.log(id); // "5" - a string, with quotes
console.log(id === 5); // false - because "5" is not the number 5
// if you need a real number, convert it
const numericId = Number(id); // 5 as a number

Quick note on this.

  • URL parts are always text, so id is "5", not 5.
  • Comparing it to a number with === will be false.
  • If you need a number, convert it with Number(id) or parseInt(id).

Params come in as strings

Even /users/5 gives you the string "5". This bites people who compare it to a number or do math on it. Convert with Number(id) when you actually need a number.

⚠️ Common Mistakes

A common mistake is reading the parameter by the wrong name, one that doesn’t match the path.

// path is "/users/:id"
// ❌ reading by a name that isn't in the path
const { userId } = useParams(); // userId is undefined
// ✅ read by the exact name from the path
const { id } = useParams();

Keep these in mind.

  • Don’t mismatch names. The key in useParams must match the :name in the path exactly.
  • Don’t forget the colon in the path. Without :, it’s a fixed path, not a parameter.
  • Don’t assume the value is a number. It’s always a string, so convert when needed.

✅ Best Practices

A few habits for route parameters.

  • Use a parameter for any page that follows a pattern but changes per item, like a profile or product page.
  • Name the parameter clearly, like :id or :slug, and read it by the same name.
  • Put the parameter in the dependency array of any effect that uses it, so the page updates when the URL changes.
  • Convert the value to a number with Number() when you need to do math or compare to numbers.

One route, endless pages

A single /products/:id route quietly handles every product you’ll ever have. That’s the whole point of parameters: write the pattern once, and it covers all the items.

🧩 What You’ve Learned

  • ✅ Route parameters let one route handle many URLs that follow a pattern
  • ✅ Mark the changing part of a path with a colon, like /users/:id
  • ✅ Read the value with useParams, using the same name you put in the path
  • ✅ Use the parameter to fetch that item’s data, with the param in the effect’s dependency array
  • ✅ Parameter values are always strings, so convert with Number() when you need a number
  • ✅ The key in useParams must match the :name in the path exactly

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    How do you mark a changing part of a path as a parameter?

    Why: A colon marks a parameter. /users/:id matches /users/1, /users/2, and so on, all with the same component.

  2. 2

    How do you read a route parameter inside the component?

    Why: useParams returns an object of the URL parameters. The keys match the :names in the path, so for /users/:id you read const { id } = useParams().

  3. 3

    What type is a route parameter value?

    Why: URL parts are text, so a param is always a string like '5'. Convert with Number(id) if you need to do math or compare to a number.

  4. 4

    Why put the parameter in a useEffect dependency array?

    Why: If you fetch based on the id, listing it as a dependency means visiting a different item's URL refetches that item's data instead of showing the old one.

🚀 What’s Next?

Now one route can serve many pages by reading a value from the URL. Next you’ll learn nested routes, where pages live inside other pages, like a settings section with its own sub-pages.

React Nested Routes

Share & Connect