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 always string | 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

React
// App.tsx (children){ path: 'products/:productId', element: <ProductDetailPage /> }
React
// pages/ProductDetail.tsximport { useParams } from "react-router";​export default function ProductDetailPage() {  const { productId } = useParams<{ productId: string }>();​  return (    <>      <h1>Product Details</h1>      <p>{productId}</p>    </>  );}
React
// 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.

Angular
// app.routes.ts{ path: 'products/:productId', component: ProductDetailComponent }
Angular
@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 useParams key (React) or the input name (Angular).

Quick reference

ReactAngular
path: 'products/:productId'path: 'products/:productId'
useParams().productIdproductId = input.required<string>()
to={`/products/${id}`}[routerLink]="['/products', id]"