Check your version
This post assumes you're using React Router v6. If not, find your version below.

If you’re reading this, you’re probably familiar with the idea of function parameters. They allow you to declare placeholders when you define a function that will be set when the function is invoked.

function getProfile (handle) {
// `handle` is a placeholder
// for when `getProfile` is invoked
}
getProfile('tylermcginnis')
getProfile('cassidoo')

URL parameters solve a similar problem, except instead of declaring placeholders for a function, you can declare placeholders for a URL. In terms of React and React Router, this means what you render can be dynamic based on the “placeholder” portion of the URL.

Take Twitter for example. Instead of defining a route for every user on the platform, they can declare one route with a placeholder of the user’s handle. The syntax would look something like this,

<Route path=':handle' element={<Profile />} />

Notice that the path has a : in front of it. That’s how you tell React Router that this portion of the URL is the “placeholder”. Instead of matching literally for twitter.com/handle, it’s matching for the specific pattern.

Now whenever anyone visits a URL that matches the :handle pattern (/tylermcginnis, /cassidoo, /anything) , the Profile component.

Now the question becomes, how do you access the dynamic portion of the URL – in this case, handle – in the component that’s rendered?

As of v5.1, React Router comes with a useParams Hook that returns an object with a mapping between the URL parameter and its value.

import * as React from 'react'
import { useParams } from 'react-router-dom'
import { getProfile } from '../utils'
function Profile () {
const [user, setUser] = React.useState(null)
const { handle } = useParams()
React.useEffect(() => {
getProfile(handle)
.then(setUser)
}, [handle])
return (
...
)
}

Now that we have the fundamentals out of the way, let’s look at an example where we’d need to use URL parameters in an app – building a blog.

Our blog will be simple. On the / page we’ll list out and link to all of our blog posts and we’ll create a URL parameter for each post at /blog/:id.

With only that information, we can already render our Routes.

import * as React from "react";
import {
BrowserRouter as Router,
Route,
Routes,
} from "react-router-dom";
function Home() {
return ();
}
function Post() {
return ();
}
export default function App() {
return (
<Router>
<Routes>
<Route
path="/"
element={<Home />}
/>
<Route
path="blog/:id"
element={<Post />}
/>
</Routes>
</Router>
);
}

Next let’s build out the Home component. As we learned earlier, this component will “list out and link to all of our blog posts”. To do this, we’ll need a way to get all of the ids and titles for our posts. Because this is a post about URL parameters, let’s pretend we already had a helper function to give us this info - getPosts.

import * as React from "react";
import {
BrowserRouter as Router,
Route,
Routes,
Link,
} from "react-router-dom";
import { getPosts } from "./api";
function Home() {
const posts = getPosts();
return (
<div>
<h1>Posts</h1>
<nav>
<ul>
{posts.map(({ id, title }) => (
<li key={id}>
<Link to={`blog/${id}`}>{title}</Link>
</li>
))}
</ul>
</nav>
</div>
);
}
...

The biggest thing to note in the code above is the <Link> component. Notice we’re linking to blog/${id} because that’s the pattern that matches our Route we created previously -

<Route path="blog/:id" element={<Post />} />

The final thing we need is to build out our Post component that gets rendered when a user visits a URL that matches the blog/:id pattern. To do this, we’ll need to first, get the id of the post the user is visting (via the URL parameter) and second, use that id to get the contents of the post.

To get the id of the post (via the URL parameter), we can use React Router’s useParams Hook. To then get the post’s content, we’ll pretend we have a getPost function we can use.

import * as React from "react";
import {
BrowserRouter as Router,
Link,
Route,
Routes,
useParams
} from "react-router-dom";
import { getPost, getPosts } from "./api";
function Post() {
const { id } = useParams();
const post = getPost(id);
return (
<div>
<h1>{post.title}</h1>
<p>{post.content}</p>
</div>
);
}

To recap, you can think of URL parameters similar to how you think of function parameters. However, instead of creating a placeholder for a function value, you’re creating a placeholder for a portion of a URL.

Using React Router, when you want to create a Route that uses a URL parameter, you do so by including a : in front of the value you pass to Route’s path prop.

<Route path=':id' element={<Invoice />} />

Finally, to access the value of the URL parameter from inside of the component that is rendered by React Router, you can use React Router’s useParams Hook.

import { useParams } from 'react-router-dom'
export default function Invoice () {
const { id } = useParams()
...
}
Want to learn more?
If you liked this post and want to learn more, check out our free Comprehensive Guide to React Router.

Before you leave

I know, "another newsletter pitch" - but hear me out. Most JavaScript newsletters are terrible. When's the last time you actually looked forward to getting one? Even worse, when's the last time you actually read one rather than just skim it?

We wanted to change that, which is why we created Bytes. The goal was to create a JavaScript newsletter that was both educational and entertaining. 84,338 subscribers and an almost 50% weekly open rate later, it looks like we did it.

Delivered to 84,338 developers every Monday

Avatar for Tyler McGinnis

Tyler McGinnis

CEO of ui.dev. Obsessed with teaching, writing, swimming, biking, and running.

Share this post

Want more react-router?

This is part of our React Router course. You can take the rest of the course by starting a free 3-day trial.