Building a Multi-Page SPA with React RouterEntry 8 of 20
Path Params with useParams
A dynamic segment (:paramName) in a route path captures part of the URL, and useParams() reads it.
Notes
path: 'products/:productId'matches/products/p1,/products/p2, and so on.useParams()returns an object keyed by segment name. Values are alwaysstring | undefined.- Link to dynamic routes with template strings:
to={`/products/${product.id}`}.
What / Why / When
- What
Variable parts of a URL.
- Why
One route and one component for every item.
- When
Detail pages, edit pages, anything identified by an ID.
Code compare
// App.tsx (children){ path: 'products/:productId', element: <ProductDetailPage /> }// pages/ProductDetail.tsximport { useParams } from "react-router";export default function ProductDetailPage() { const { productId } = useParams<{ productId: string }>(); return ( <> <h1>Product Details</h1> <p>{productId}</p> </> );}// pages/Products.tsx<li key={product.id}> <Link to={`/products/${product.id}`}>{product.title}</Link></li>With withComponentInputBinding(), route params bind straight to inputs with the same name.
// app.routes.ts{ path: 'products/:productId', component: ProductDetailComponent }@Component({ selector: "app-product-detail", template: ` <h1>Product Details</h1> <p>{{ productId() }}</p> `,})export class ProductDetailComponent { productId = input.required<string>();}Differences and gotchas
- Without input binding, Angular reads params with
inject(ActivatedRoute).paramMap. - The param name in the route must match the
useParamskey (React) or the input name (Angular).
Quick reference
| React | Angular |
|---|---|
path: 'products/:productId' | path: 'products/:productId' |
useParams().productId | productId = input.required<string>() |
to={`/products/${id}`} | [routerLink]="['/products', id]" |