Parámetros de ruta y ubicación
Una página de lista y una página de detalle son la dupla clásica en una app ruteada: /vans muestra todas las camionetas, y hacer clic en una debe abrir /vans/2 con los detalles de esa camioneta. Escribir una ruta separada para cada camioneta significaría tocar el router cada vez que los datos cambian. Los parámetros de ruta resuelven esto con una sola definición de ruta que coincida con todas ellas: un marcador de posición en la ruta captura cualquier valor que aparezca allí, y la página lee ese valor para traer los datos correctos. Este capítulo cubre ese patrón, más un truco relacionado: pasar información extra junto con una navegación, para que una página de detalle pueda recordar cosas como qué filtro tenía aplicado la lista.
Segmentos dinámicos y useParams
Un segmento dinámico es una sección de ruta que comienza con dos puntos. En lugar de coincidir con texto literal, coincide con cualquier cosa en esa posición y guarda el valor bajo el nombre que elegiste:
<Route path="/vans/:id" element={<VanDetail />} />Ahora /vans/1, /vans/42 y /vans/anything todas renderizan VanDetail. Los dos puntos marcan id como una variable dentro de la ruta. Piénsalo como un parámetro de función: la definición de ruta se escribe una sola vez, y la URL proporciona el argumento. La página de lista vincula cada elemento a su propia URL con el componente Link de Routing, usualmente interpolando el id mientras mapeas sobre los datos:
{vans.map(van => (
<Link key={van.id} to={`/vans/${van.id}`}>
<h3>{van.name}</h3>
</Link>
))}Del otro lado, el hook useParams devuelve un objeto con una propiedad por cada segmento dinámico en la ruta coincidente, indexada por el nombre después de los dos puntos:
import { useParams } from 'react-router-dom'
export default function VanDetail() {
const params = useParams()
// en /vans/2 → { id: "2" }
return <h1>Van #{params.id}</h1>
}Una ruta puede contener varios segmentos, como /vans/:id/:type, y cada uno aparece como su propia clave. Un parámetro coincidente siempre es una string, incluso cuando parece un número, porque viene directo de la URL.
Traer datos para el parámetro
El parámetro usualmente es la clave para una búsqueda. La página de detalle toma el id de la URL y solicita ese registro, siguiendo el patrón basado en efectos que Fetching data cubre completamente:
import { useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'
export default function VanDetail() {
const { id } = useParams()
const [van, setVan] = useState(null)
const [error, setError] = useState(null)
useEffect(() => {
let active = true
setVan(null)
setError(null)
fetch(`/api/vans/${id}`)
.then(res => {
if (!res.ok) throw new Error(`Request failed: ${res.status}`)
return res.json()
})
.then(data => { if (active) setVan(data.vans) })
.catch(err => { if (active) setError(err) })
return () => { active = false }
}, [id])
if (error) return <h2>Disculpa, no pudimos cargar esa camioneta.</h2>
return van ? <h1>{van.name}</h1> : <h2>Cargando...</h2>
}El array de dependencias tiene id en lugar de estar vacío. Si la app alguna vez navega de una página de detalle a otra, digamos en una sección de "camionetas similares", React Router intercambia la URL y el parámetro sin desmontar el componente. Un array vacío saltaría la búsqueda nuevamente y dejaría la camioneta anterior en pantalla. Depender de id vuelve a ejecutar el efecto, y limpiar van al principio de la ejecución es la parte que devuelve "Cargando..." a la pantalla: sin eso, el nombre de la camioneta 2 seguiría renderizándose durante toda la duración de la solicitud de la camioneta 5.
La verificación res.ok, el catch y el flag de limpieza active son las mismas protecciones que Fetching data argumenta, y una página impulsada por parámetros las necesita más que la mayoría: el id viene de una barra de direcciones que cualquiera puede editar, y hacer clic rápidamente a través de páginas de detalle es cómo una respuesta de la camioneta que ya dejaste llega después de la que estás viendo.
Pasar estado a través de un Link
Los parámetros llevan datos de la URL a una página. A veces una página también quiere saber algo sobre de dónde vino el visitante. En el proyecto VanLife del curso, la página de lista puede filtrarse hacia, digamos, solo camionetas de lujo. Haz clic en una, presiona "Volver a todas las camionetas", y un simple link de atrás te lleva a la lista sin filtrar: el filtro se pierde, lo que se vuelve molesto rápidamente una vez que varios filtros están involucrados.
Una solución sería copiar la query string a la URL de la página de detalle, y Search params cubre cuándo el estado basado en URL como ese es lo correcto: sobrevive a compartir el link con alguien más. Cuando la información es una comodidad UX para el visitante actual, React Router ofrece un canal más ligero. Link acepta una prop state, y cualquier cosa que pases viaja junto con la navegación sin aparecer en la URL:
<Link
to={`/vans/${van.id}`}
state={{ search: `?${searchParams.toString()}`, type: typeFilter }}
>
<h3>{van.name}</h3>
</Link>searchParams y typeFilter son los valores propios de useSearchParams de la página de lista, del hook que Search params cubre completamente a continuación, así que el link lleva la query string completa más el nombre de filtro actual. Cualquier valor serializable funciona, aunque un objeto con propiedades nombradas se lee mejor.
Leerlo con useLocation
La página de destino lee ese estado con el hook useLocation, que devuelve un objeto describiendo la ubicación actual: pathname, search (la propia query string de la URL actual), y state, que contiene lo que el Link entrante pasó:
import { Link, useLocation } from 'react-router-dom'
export default function VanDetail() {
const location = useLocation()
const search = location.state?.search || ''
const type = location.state?.type || 'all'
return (
<Link to={`..${search}`} relative="path">
← Volver a {type} camionetas
</Link>
)
}Los dos fallbacks son la parte importante. Alguien que llega a /vans/2 directamente, desde un marcador, un link compartido, o una URL escrita, llega con location.state establecido en null porque ningún Link los envió. Leer location.state.search entonces lanzaría un error, así que el encadenamiento opcional más un fallback mantiene la página funcionando: el link de atrás va a la lista simple y el texto dice "Volver a todas las camionetas". Con estado presente, el link restaura la query string exacta y el texto se vuelve "Volver a camionetas de lujo" o lo que sea que fue el filtro.
La prop relative="path" hace que .. suba un segmento de URL en lugar de un nivel en el árbol de rutas, lo que importa cuando la ruta de detalle tiene un padre diferente de lo que la URL sugiere. Nested routes explica esa distinción.
El camino difícil en una página impulsada por parámetros
El curso enmarca el manejo de errores como camino feliz versus camino difícil: el camino feliz asume que cada solicitud tiene éxito, el camino difícil planifica para las que no. La mecánica de carga y error en sí pertenece a Fetching data: carga derivada del resultado y el error ambos siendo aún vacíos, un estado error establecido en el catch, y returns tempranos que renderizan retroalimentación en lugar de estrellarse en datos faltantes.
Lo que este capítulo agrega es que las páginas impulsadas por parámetros multiplican los caminos difíciles. La URL es entrada editable por el usuario, así que /vans/999 está a un teclado de distancia y el servidor responderá con un 404 para un id que no existe; la verificación res.ok arriba es lo que convierte esa respuesta en estado de error y un mensaje en lugar de un objeto con forma de camioneta. Y como se cubre arriba, el estado de navegación puede estar ausente. Una página que llega a la red a través de un parámetro debe asumir que el parámetro puede estar mal, la solicitud puede fallar, y el estado puede ser null, y renderizar algo sensato en cada caso.
Nota de versión
Antes de React Router v5.1, la información de ruta llegaba solo como props: los componentes leían props.match.params y props.location. La versión 5.1 agregó los hooks useParams y useLocation, y la versión 6 eliminó la API basada en props, dejando los hooks como la única forma de acceder. Cualquier componente bajo el router puede llamarlos, sin importar cuán profundo renderice.
/vans/:id, crea un espacio en blanco que cualquier valor puede llenar, así que una ruta sirve una página de detalle para cada elemento en tu lista. Dentro de la página, useParams te entrega ese valor para que puedas traer los datos correctos. Los links también pueden llevar un pequeño paquete de información extra a través de su prop state, y useLocation lo lee del otro lado. Recuerda que el paquete podría estar faltando si alguien llegó desde un marcador, así que siempre ten un fallback listo.
Próximo: Search params, donde los filtros y órdenes de clasificación viven en la URL.

