React Route Parameters
Table of Contents + −
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/1and/users/2show different people. - A product page like
/products/42changes per product. - You can’t write one
Routeper 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/:idhas a fixed part,/users/, and a parameter,:id.- The
:idmatches whatever comes after/users/, like1,42, orabc. - 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
:idgives you anid. - So
const { id } = useParams()pulls the id out, ready to use. - Visit
/users/5andidis"5"; visit/users/9andidis"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.
useParamsgives theidfrom the URL, like5.- We put that id straight into the fetch URL, so we load that exact user.
idis 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 quotesconsole.log(id === 5); // false - because "5" is not the number 5
// if you need a real number, convert itconst numericId = Number(id); // 5 as a numberQuick note on this.
- URL parts are always text, so
idis"5", not5. - Comparing it to a number with
===will befalse. - If you need a number, convert it with
Number(id)orparseInt(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 pathconst { userId } = useParams(); // userId is undefined
// ✅ read by the exact name from the pathconst { id } = useParams();Keep these in mind.
- Don’t mismatch names. The key in
useParamsmust match the:namein 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
:idor: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
useParamsmust match the:namein the path exactly
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 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
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
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
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.