Incorrect Use of useParams() When Destructuring
The useParams() hook from React Router is used to access URL parameters in functional components. A common mistake is destructuring the result of useParams() incorrectly, which can lead to unexpected errors or undefined values.
Common Mistake Example (Incorrect Destructuring):
import { useParams } from 'react-router-dom';
function Profile() {
const { userId } = useParams; // ❌ Incorrect: Missing parentheses
return <h1>Profile of User {userId}</h1>;
}
Issues:
- Missing Parentheses:
useParamsis a function and needs to be called with(). - Result:
userIdwill beundefinedbecauseuseParamswasn’t invoked.
✅ Correct Way (Proper Destructuring):
import { useParams } from 'react-router-dom';
function Profile() {
const { userId } = useParams(); // ✅ Correct: Calling the function
return <h1>Profile of User {userId}</h1>;
}
Why This Works:
useParams()returns an object containing the URL parameters.- Destructuring
{ userId }correctly extracts theuserIdfrom the returned object.
Another Common Mistake (Incorrect Structure):
function Dashboard() {
const { id, name } = useParams(); // ❌ Incorrect if params don't include both
return <h2>Dashboard for {name}</h2>;
}
Potential Issue:
- If the route is
/dashboard/:idwithout anameparam,namewill beundefined. - Fix: Ensure the route matches the parameters or provide default values:
const { id, name = 'Guest' } = useParams(); // ✅ Default value for missing params
Bonus: Using useParams() with Nested Routes
import { useParams } from 'react-router-dom';
function ProductDetail() {
const { categoryId, productId } = useParams(); // ✅ Multiple params
return (
<div>
<h1>Product ID: {productId}</h1>
<p>Category: {categoryId}</p>
</div>
);
}
Route Example:
<Route path="/category/:categoryId/product/:productId" element={<ProductDetail />} />
- Why This Works:
useParams()returns{ categoryId: '123', productId: '456' }.- You can destructure multiple parameters easily.
Incorrectly Accessing Parameters Inside useEffect
import { useParams } from 'react-router-dom';
import { useEffect } from 'react';
function Product() {
const { productId } = useParams();
useEffect(() => {
console.log(productId); // ✅ Works if productId is available
}, [productId]); // ✅ Proper dependency
return <h1>Product Details</h1>;
}
Issue to Avoid:
- Dependency Mistake: Forgetting to add
productIdto the dependency array can cause stale data issues.
Bonus: Handling Missing Params Gracefully
function UserProfile() {
const { userId } = useParams();
if (!userId) {
return <h2>No User ID Provided</h2>; // ✅ Graceful handling
}
return <h1>User ID: {userId}</h1>;
}
- Why This Works:
Prevents rendering issues when the URL doesn’t contain the expected parameters.
Common Mistake: Using useParams in Class Components (Incorrect)
// ❌ Incorrect: useParams can't be used in class components
class Product extends React.Component {
render() {
const { productId } = useParams(); // ❌ Error: Hook can’t be called in class components
return <h1>Product {productId}</h1>;
}
}
Fix:
Use functional components with hooks:
function Product() {
const { productId } = useParams(); // ✅ Correct
return <h1>Product {productId}</h1>;
}
Bonus: TypeScript Example (with useParams Types)
import { useParams } from 'react-router-dom';
interface Params {
userId: string;
}
function UserProfile() {
const { userId } = useParams<Params>(); // ✅ Type safety with TypeScript
return <h1>User ID: {userId}</h1>;
}
- Why This Works:
Provides type safety for the URL parameters, reducing runtime errors.
Final Common Pitfall: Overcomplicating Destructuring
// ❌ Overcomplicating destructuring unnecessarily
const { userId: { value } } = useParams(); // ❌ Error: userId is a string, not an object
Fix:
Just destructure the value directly:
const { userId } = useParams(); // ✅ Correct
Key Takeaways:
- Always call
useParams()with parentheses:useParams(). - Match the route parameters correctly when destructuring.
- Use default values or error handling for missing params.
- Don’t use
useParamsin class components — it’s a hook for functional components.
