useParams
Returns an object of key/value pairs of the dynamic params from the current URL that were matched by the routes. Child routes inherit all params from their parent routes.
Signature
function useParams<
ParamsOrKey extends string | Record<string, string | undefined> = string
>(): Readonly<
[ParamsOrKey] extends [string] ? Params<ParamsOrKey> : Partial<ParamsOrKey>
>
Parameters
None.
Returns
params
Record<string, string | undefined>
An object containing the URL parameters from the matched route. All values are strings or undefined.
Usage
Basic usage
Given a route pattern like /posts/:postId:
import { useParams } from "react-router";
// Route definition
<Route path="/posts/:postId" element={<Post />} />
// Component
function Post() {
const params = useParams();
return <h1>Post ID: {params.postId}</h1>;
}
// URL: /posts/123
// params.postId === "123"
Multiple params
Patterns can have multiple params:
// Route: /posts/:postId/comments/:commentId
<Route
path="/posts/:postId/comments/:commentId"
element={<Comment />}
/>
function Comment() {
const params = useParams();
return (
<div>
<h1>Post: {params.postId}</h1>
<h2>Comment: {params.commentId}</h2>
</div>
);
}
// URL: /posts/123/comments/456
// params.postId === "123"
// params.commentId === "456"
Catchall params
Catchall params are defined with *:
// Route: /files/*
<Route path="/files/*" element={<Files />} />
function Files() {
const params = useParams();
const filepath = params["*"];
return <h1>File: {filepath}</h1>;
}
// URL: /files/documents/report.pdf
// params["*"] === "documents/report.pdf"
You can destructure the catchall param:
function Files() {
const { "*": filepath } = useParams();
return <h1>File: {filepath}</h1>;
}
Named catchall params
You can also name catchall params:
// Route: /files/:path*
<Route path="/files/:path*" element={<Files />} />
function Files() {
const { path } = useParams();
return <h1>File: {path}</h1>;
}
Using in loaders
Params are available in route loaders:
import { useLoaderData } from "react-router";
export async function loader({ params }) {
const post = await fetchPost(params.postId);
return { post };
}
export default function Post() {
const { post } = useLoaderData();
return <h1>{post.title}</h1>;
}
Parent route params
Child routes inherit all params from parent routes:
// Parent route: /users/:userId
<Route path="/users/:userId" element={<UserLayout />}>
{/* Child route: /users/:userId/posts/:postId */}
<Route path="posts/:postId" element={<Post />} />
</Route>
function Post() {
const params = useParams();
// Both userId and postId are available
console.log(params.userId); // from parent
console.log(params.postId); // from child
}
// URL: /users/42/posts/123
// params.userId === "42"
// params.postId === "123"
Type Safety
Generic type parameter
You can provide a type for better type checking:
interface Params {
userId: string;
postId: string;
}
function Post() {
const params = useParams<Params>();
// TypeScript knows these are strings | undefined
params.userId; // string | undefined
params.postId; // string | undefined
}
With route loader types
In Framework mode, types are automatically generated:
import type { Route } from "./+types.post";
export async function loader({ params }: Route.LoaderArgs) {
// params is automatically typed
const post = await fetchPost(params.postId);
return { post };
}
export default function Post() {
const params = useParams<Route.Params>();
// params is fully typed
}
Runtime validation
Since params can be undefined, validate them at runtime:
function Post() {
const params = useParams();
if (!params.postId) {
return <div>Invalid post ID</div>;
}
// Now safe to use params.postId
const postId = params.postId;
}
Common Patterns
Convert to number
Params are always strings. Convert to numbers as needed:
function Post() {
const params = useParams();
const postId = Number(params.postId);
if (isNaN(postId)) {
return <div>Invalid post ID</div>;
}
// Use postId as a number
}
URL decode params
Params are automatically URL-decoded:
// URL: /posts/hello%20world
// params.postId === "hello world"
Optional params
Make params optional with ?:
// Route: /posts/:postId?
<Route path="/posts/:postId?" element={<Posts />} />
function Posts() {
const params = useParams();
if (params.postId) {
return <Post id={params.postId} />;
}
return <PostList />;
}