Parâmetros de rota e localização
Uma página de lista e uma página de detalhe formam o par clássico em um app com rotas: /vans mostra todas as vans, e clicar em uma deve abrir /vans/2 com os detalhes dessa van. Escrever uma rota separada para cada van significaria mexer no roteador cada vez que os dados mudassem. Parâmetros de rota resolvem isso com uma única definição de rota que captura todos: um espaço reservado no caminho guarda o valor que aparecer ali, e a página lê esse valor para buscar os dados certos. Este capítulo cobre esse padrão, mais um truque relacionado: passar informações extras junto com uma navegação, para que uma página de detalhe lembre de coisas como qual filtro a lista tinha aplicado.
Segmentos dinâmicos e useParams
Um segmento dinâmico é uma seção do caminho que começa com dois-pontos. Em vez de capturar texto literal, ele captura qualquer coisa naquela posição e guarda o valor sob o nome que você escolheu:
<Route path="/vans/:id" element={<VanDetail />} />Agora /vans/1, /vans/42 e /vans/qualquercoisa renderizam VanDetail. Os dois-pontos marcam id como uma variável dentro do caminho. Pense nisto como um parâmetro de função: a definição da rota é escrita uma vez, e a URL fornece o argumento. A página de lista linka cada item para sua própria URL com o componente Link de Routing, normalmente interpolando o id enquanto percorre os dados:
{vans.map(van => (
<Link key={van.id} to={`/vans/${van.id}`}>
<h3>{van.name}</h3>
</Link>
))}Do outro lado, o hook useParams retorna um objeto com uma propriedade por segmento dinâmico no caminho capturado, com chaves pelo nome após os dois-pontos:
import { useParams } from 'react-router-dom'
export default function VanDetail() {
const params = useParams()
// em /vans/2 → { id: "2" }
return <h1>Van #{params.id}</h1>
}Um caminho pode conter vários segmentos, como /vans/:id/:type, e cada um aparece como sua própria chave. Um parâmetro capturado é sempre uma string, mesmo quando parece um número, porque vem direto da URL.
Buscando dados para o parâmetro
O parâmetro é normalmente a chave para uma busca. A página de detalhe pega o id da URL e requisita aquele registro, seguindo o padrão baseado em efeitos que Fetching data cobre em profundidade:
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>Desculpe, não conseguimos carregar essa van.</h2>
return van ? <h1>{van.name}</h1> : <h2>Carregando...</h2>
}O array de dependências mantém id em vez de ficar vazio. Se o app alguma vez linkiar de uma página de detalhe para outra, digamos uma seção de "vans similares", React Router troca a URL e o parâmetro sem desmontar o componente. Um array vazio pularia a nova busca e deixaria a van antiga na tela. Depender de id reroda o efeito, e limpar van no topo da execução é o que coloca "Carregando..." de volta na tela: sem isso, o nome da van 2 continua renderizando por todo o tempo que a requisição da van 5 leva.
A verificação res.ok, o catch e o flag de limpeza active são as mesmas proteções que Fetching data argumenta favor de, e uma página acionada por parâmetro precisa delas mais que a maioria: o id chega de uma barra de endereços que qualquer um pode editar, e clicar rapidamente através de páginas de detalhe é como uma resposta para a van que você já saiu chega depois da que você está vendo.
Passando state através de um Link
Parâmetros carregam dados da URL para uma página. Às vezes uma página também quer saber algo sobre de onde o visitante veio. No projeto VanLife do curso, a página de lista pode ser filtrada para, digamos, apenas vans de luxo. Clique em uma, aperte "Voltar para todas as vans", e um link simples de volta pousa na lista sem filtro: o filtro se perde, o que fica chato rápido quando vários filtros estão envolvidos.
Uma solução seria copiar a query string para a URL da página de detalhe, e Search params cobre quando estado transportado pela URL assim é a chamada certa: sobrevive compartilhar o link com alguém. Quando a informação é uma gentileza de UX para o visitante atual, React Router oferece um canal mais leve. Link aceita uma prop state, e o que você passa viaja com a navegação sem aparecer na URL:
<Link
to={`/vans/${van.id}`}
state={{ search: `?${searchParams.toString()}`, type: typeFilter }}
>
<h3>{van.name}</h3>
</Link>searchParams e typeFilter são os próprios valores useSearchParams da página de lista, do hook que Search params cobre em profundidade a seguir, então o link carrega a query string completa mais o nome do filtro atual. Qualquer valor serializável funciona, embora um objeto com propriedades nomeadas leia melhor.
Lendo com useLocation
A página de destino lê aquele state com o hook useLocation, que retorna um objeto descrevendo a localização atual: pathname, search (a própria query string da URL atual), e state, que guarda o que o Link de entrada passou:
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">
← Voltar para vans {type}
</Link>
)
}Os dois fallbacks são a parte importante. Alguém que chega em /vans/2 diretamente, de um marcador, um link compartilhado, ou uma URL digitada, chega com location.state definido como null porque nenhum Link o enviou. Ler location.state.search então lançaria um erro, então o encadeamento opcional mais um fallback mantém a página funcionando: o link de volta vai para a lista simples e o texto lê "Voltar para todas as vans". Com state presente, o link restaura a query string exata e o texto fica "Voltar para vans de luxo" ou o que quer que o filtro fosse.
A prop relative="path" faz .. subir um segmento de URL em vez de um nível na árvore de rotas, o que importa quando a rota de detalhe tem um pai diferente do que sua URL sugere. Nested routes explica essa distinção.
O caminho triste em uma página acionada por parâmetro
O curso enquadra tratamento de erros como caminho feliz versus caminho triste: o caminho feliz assume que cada requisição sucede, o caminho triste se prepara para as que não. A própria mecânica de carregamento e erro pertence a Fetching data: carregamento derivado do resultado e do erro ainda estando vazios, um state error definido no catch, e retornos antecipados que renderizam feedback em vez de quebrar em dados ausentes.
O que este capítulo adiciona é que páginas acionadas por parâmetro multiplicam os caminhos tristes. A URL é entrada editável pelo usuário, então /vans/999 é um pressionamento de tecla de distância e o servidor responderá com um 404 para um id que não existe; a verificação res.ok acima é o que transforma aquela resposta em error state e uma mensagem em vez de um objeto em forma de van. E como coberto acima, o state de navegação pode estar ausente. Uma página que alcança a rede através de um parâmetro deve assumir que o parâmetro pode estar errado, a requisição pode falhar, e o state pode ser null, e renderizar algo sensato em cada caso.
Nota de versão
Antes do React Router v5.1, informações de rota chegavam apenas como props: componentes liam props.match.params e props.location. A versão 5.1 adicionou os hooks useParams e useLocation, e a versão 6 removeu a API baseada em props, deixando os hooks como a única forma de entrar. Qualquer componente sob o roteador pode chamá-los, porém profundamente renderize.
/vans/:id, criam um espaço que qualquer valor pode preencher, então uma rota serve uma página de detalhe para cada item na sua lista. Dentro da página, useParams te passa aquele valor para você buscar os dados certos. Links também podem carregar um pequeno pacote de informação extra através de sua prop state, e useLocation lê do outro lado. Lembre que o pacote pode estar ausente se alguém chegou de um marcador, então sempre tenha um fallback pronto.
Próximo: Search params, onde filtros e ordens de classificação vivem na URL.

