useParams
Access path parameters from the current route with type safety.
The useParams hook returns path parameters from the current route and its parent routes. It provides type-safe access to dynamic URL segments defined with the $ syntax.
Basic usage
Get all parameters
Access all path parameters with type safety:
import { useParams } from "@tanstack/react-router";
function PostPage() {
const params = useParams({ from: "/posts/$postId" });
// params has type-safe access to postId
return <div>Post ID: {params.postId}</div>;
}Using Route API
For route components, use the Route API for automatic typing:
import { getRouteApi } from "@tanstack/react-router";
const routeApi = getRouteApi("/posts/$postId");
function PostComponent() {
const params = routeApi.useParams();
// Automatically typed for this route
return <div>Post: {params.postId}</div>;
}Good to know: Always provide the
fromoption for better type safety and performance. In route components, useRoute.useParams()instead.
Select specific parameters
Use select to extract only the parameters you need:
function Component() {
const postId = useParams({
from: "/posts/$postId",
select: (params) => params.postId,
});
return <div>Post ID: {postId}</div>;
}This prevents unnecessary re-renders when other parameters change.
Options
Loose typing
Get parameters from any route without strict typing:
function Component() {
// Get params from any route (loose typing)
const looseParams = useParams({ strict: false });
// postId might be undefined
return <div>{looseParams.postId || "No post ID"}</div>;
}Note: Avoid
strict: falsewhen possible. It reduces type safety and makes your code less maintainable.
No throw
Prevent errors when the route doesn't match:
function Component() {
// Don't throw if no match found
const params = useParams({
from: "/posts/$postId",
shouldThrow: false,
});
if (!params) return <div>No params available</div>;
return <div>Post: {params.postId}</div>;
}Common use cases
Nested routes
Access parameters from nested routes:
// Parent route: /users/$userId
// Child route: /users/$userId/posts/$postId
function UserPostComponent() {
const params = useParams({
from: "/users/$userId/posts/$postId",
});
// Access both userId and postId
return (
<div>
User: {params.userId}
Post: {params.postId}
</div>
);
}Conditional rendering
Use parameters to conditionally render content:
function PostComponent() {
const hasId = useParams({
from: "/posts/$postId",
select: (params) => Boolean(params.postId),
});
if (!hasId) return <div>No post selected</div>;
return <PostContent />;
}Custom hooks
Create reusable hooks for common parameter patterns:
function usePostId() {
return useParams({
from: "/posts/$postId",
select: (params) => params.postId,
});
}
function useCurrentUser() {
return useParams({
from: "/users/$userId",
select: (params) => params.userId,
});
}
// Usage
function Component() {
const postId = usePostId();
const userId = useCurrentUser();
return (
<div>
User {userId} viewing post {postId}
</div>
);
}Parameter validation
Validate parameters before using them:
function PostPage() {
const postId = useParams({
from: "/posts/$postId",
select: (params) => params.postId,
});
useEffect(() => {
if (!postId || !/^\d+$/.test(postId)) {
// Handle invalid postId
console.error("Invalid post ID");
}
}, [postId]);
return <div>Post {postId}</div>;
}Best practices
Use from option
Always provide the from option for better type safety and performance:
// ✅ Good - Type-safe
const params = useParams({ from: "/posts/$postId" });
// ⚠️ Avoid - Less type-safe
const params = useParams({ strict: false });Prefer Route API in route components
Use Route.useParams() in route components for automatic typing:
// ✅ Good - In route component
export const Route = createFileRoute("/posts/$postId")({
component: PostPage,
});
function PostPage() {
const params = Route.useParams();
return <div>{params.postId}</div>;
}
// ⚠️ Works but less convenient
function PostPage() {
const params = useParams({ from: "/posts/$postId" });
return <div>{params.postId}</div>;
}Use select for performance
Extract only the parameters you need to prevent unnecessary re-renders:
// ❌ Bad - Re-renders when any param changes
function BadExample() {
const params = useParams({ from: "/posts/$postId" });
return <div>{params.postId}</div>;
}
// ✅ Good - Only re-renders when postId changes
function GoodExample() {
const postId = useParams({
from: "/posts/$postId",
select: (params) => params.postId,
});
return <div>{postId}</div>;
}Handle undefined values
Always handle undefined when using strict: false or shouldThrow: false:
// ✅ Good - Handles undefined
function Component() {
const params = useParams({
from: "/posts/$postId",
shouldThrow: false,
});
if (!params) return <div>No params available</div>;
return <div>{params.postId}</div>;
}
// ❌ Bad - Assumes params exists
function Component() {
const params = useParams({
from: "/posts/$postId",
shouldThrow: false,
});
return <div>{params.postId}</div>; // Could be undefined!
}Performance optimization
The select option is crucial for performance. It prevents re-renders when unrelated parameters change:
// ❌ Re-renders when any param changes
function BadExample() {
const params = useParams({ from: "/posts/$postId" });
return <div>{params.postId}</div>;
}
// ✅ Only re-renders when postId changes
function GoodExample() {
const postId = useParams({
from: "/posts/$postId",
select: (params) => params.postId,
});
return <div>{postId}</div>;
}When to use select:
- When you only need specific parameters
- When you want to prevent unnecessary re-renders
- When extracting derived values from parameters
When not to use select:
- When you need all parameters
- When the selector function is complex (consider memoization)