Skip to content
This page has been auto-translated and may contain errors.View in English

Parâmetros de busca ​

Parâmetros de rota dizem ao seu app em qual página você está. Parâmetros de busca, também chamados de query params, descrevem como aquela página deve parecer: qual filtro está ativo, por qual coluna a lista está ordenada, qual página de resultados está sendo exibida. Eles vivem na URL após um ponto de interrogação, como pares chave/valor como /vans?type=rugged, com pares extras ligados por ampersands: /vans?type=rugged&sort=price. Por serem parte da URL, sobrevivem a um refresh e viajam dentro de um link compartilhado, o que os torna um tipo diferente de estado do que qualquer coisa que useState possa guardar.

Estado que pertence à URL ​

Estado mantido com useState vive na memória. Atualize a página e ele volta ao seu valor inicial; copie a URL para um amigo e ele começa do zero sem nenhuma de suas escolhas. Para muito estado isso é exatamente o certo. Para alguns, é uma perda real: se você filtrou uma lista de vans para apenas as rústicas com um preço máximo, você provavelmente quer que um refresh mantenha aquela visualização, e quer que um link colado abra a mesma lista curada para outra pessoa.

O curso oferece um teste útil: um usuário deveria ser capaz de revisitar ou compartilhar esta página exatamente como está e obter o mesmo resultado? Se sim, considere promover aquele pedaço de estado para fora do React e para a URL como um parâmetro de busca. Filtragem, ordenação e paginação são os candidatos clássicos. A URL então se torna a única fonte de verdade para aquele estado, e seu componente deriva o que renderiza a partir dela, da mesma forma que derivaria de estado ou props.

Lendo parâmetros com useSearchParams ​

React Router expõe a query string através do hook useSearchParams, e sua forma é deliberadamente próxima a useState: um array contendo o valor atual e um setter.

jsx
import { useSearchParams } from 'react-router-dom'

export default function CharacterList() {
  const [searchParams, setSearchParams] = useSearchParams()
  const typeFilter = searchParams.get('type')
  // ...
}

searchParams é uma instância do objeto nativo URLSearchParams do navegador em vez de um objeto simples, então você interage com ele através de seus métodos. .get('type') retorna o valor do parâmetro type como uma string, e retorna null quando aquele parâmetro não está na URL. Aquele null é como seu código sabe que nenhum filtro está ativo. .toString() serializa todo o conjunto de volta para uma query string como type=sith&sort=price, sem o ponto de interrogação no início.

Nota de versão

Os exemplos aqui importam de react-router-dom, o que funciona em v6 e v7; Roteamento cobre o que v7 mudou sobre os pacotes.

Filtrando uma lista a partir de um parâmetro ​

Com o parâmetro em mãos, filtrar é JavaScript puro no topo do componente. Sem estado, sem efeito: ler um parâmetro e filtrar um array são ambos rápidos, então tudo bem refazer o trabalho em cada render e deixar o resultado sair da URL.

jsx
const typeFilter = searchParams.get('type')

const displayedCharacters = typeFilter
  ? characters.filter(char => char.type.toLowerCase() === typeFilter.toLowerCase())
  : characters

const charEls = displayedCharacters.map(char => (
  <li key={char.name}>{char.name}</li>
))

O ternário trata o caso sem filtro: quando .get retorna null, a lista completa é exibida. Escolher qual array renderizar dessa forma é o mesmo movimento de derivar-ao-renderizar que você usou para renderização condicional, dirigido pela URL em vez de por estado. Cuidado também com diferenças de maiúsculas; os dados armazenam "Sith" enquanto um link editado à mão pode carregar Sith ou sith, então ambos os lados ficam em minúsculas antes de serem comparados.

A forma mais direta de colocar um parâmetro de busca na URL é um Link cujo to começa com um ponto de interrogação. React Router vê o ? no início, mantém você na rota atual, e substitui a query string, o que re-renderiza o componente e re-executa sua filtragem.

jsx
<Link to="?type=jedi">Jedi</Link>
<Link to="?type=sith">Sith</Link>
<Link to=".">Limpar</Link>

Para limpar, to="." navega até o caminho atual sem query anexada; to="" também funciona, e o curso opta pelo ponto como o mais explícito dos dois. Links funcionam melhor quando o filtro é um conjunto fixo de escolhas visíveis: eles renderizam como tags âncora reais, então os usuários podem abrir uma visualização filtrada em uma nova aba ou copiar o endereço antes de clicar.

Definindo parâmetros com a função setter ​

O segundo elemento de useSearchParams é um setter, e como o de useState ele aceita tanto um valor de substituição quanto um callback. Como um botão não é parte do ecossistema do React Router da forma que Link é, você chama o setter de um manipulador de evento ordinário.

jsx
<button onClick={() => setSearchParams({ type: 'jedi' })}>Jedi</button>
<button onClick={() => setSearchParams({ type: 'sith' })}>Sith</button>
<button onClick={() => setSearchParams({})}>Limpar</button>

O setter é flexível sobre o que aceita: uma string como '?type=jedi' (com ou sem o ponto de interrogação) funciona, mas a forma de objeto mostrada aqui é o que você verá com mais frequência, e um objeto vazio limpa tudo. Recorra ao setter quando os novos parâmetros saem de lógica em vez de um clique em uma escolha fixa: lendo valores de um formulário, respondendo à entrada enquanto o usuário digita, ou definindo vários parâmetros de uma vez.

Substituição limpa os outros parâmetros ​

Ambas as abordagens até agora hard-codam toda a query string. Tudo bem enquanto type é o único parâmetro que seu app usa, mas no momento em que a URL também carrega algo não relacionado, digamos ?name=jill&type=jedi, clicar em um daqueles links ou botões substitui toda a query string e name=jill se foi. Os botões de limpar são ainda mais drásticos: eles apagam todos os parâmetros na URL, incluindo os que este componente nunca tocou. Se você tem certeza que seu projeto terá apenas um parâmetro, hard-codar está bem. Caso contrário você quer mesclar.

Mesclando com parâmetros existentes ​

Para Links, a prop to recebe uma string, então o fix é um pequeno helper que executa durante o render: copie os parâmetros atuais para um novo URLSearchParams, mude a chave que está se movendo, e serialize o resultado. Ele vive dentro do componente, já que lê searchParams do hook.

jsx
// dentro de CharacterList, para que possa ler searchParams
function genNewSearchParamString(key, value) {
  const sp = new URLSearchParams(searchParams)
  if (value === null) {
    sp.delete(key)
  } else {
    sp.set(key, value)
  }
  return `?${sp.toString()}`
}
jsx
<Link to={genNewSearchParamString('type', 'jedi')}>Jedi</Link>
<Link to={genNewSearchParamString('type', 'sith')}>Sith</Link>
<Link to={genNewSearchParamString('type', null)}>Limpar</Link>

Isso é JavaScript vanilla em vez de qualquer coisa que React Router oferece. O construtor URLSearchParams aceita felizmente um objeto de parâmetros existente como seu ponto de partida, .set atualiza ou adiciona uma chave, e passar null sinaliza ao helper para .delete a chave em vez disso, então "Limpar" agora remove apenas type e deixa tudo mais na URL intacto.

Para o setter, use seu formulário callback. O callback recebe o objeto de parâmetros anterior, você ajusta a chave, e a retorna.

jsx
// dentro de CharacterList, para que possa chamar setSearchParams
function handleFilterChange(key, value) {
  setSearchParams(prevParams => {
    if (value === null) {
      prevParams.delete(key)
    } else {
      prevParams.set(key, value)
    }
    return prevParams
  })
}
jsx
<button onClick={() => handleFilterChange('type', 'jedi')}>Jedi</button>
<button onClick={() => handleFilterChange('type', null)}>Limpar</button>

Uma surpresa que o curso chama atenção: diferente de um updater de useState, onde mutar o estado anterior é proibido, aqui é ok chamar .delete e .set diretamente em prevParams e retorná-lo. Agora tanto os links quanto os botões mudam apenas o parâmetro que eles possuem.

A mutação ser segura é uma consequência do que o setter realmente faz. Quando você dispõe uma atualização useState, React compara o novo valor com o atual com Object.is antes de agendar um re-render, então retornar o mesmo objeto mutado lê-se como nenhuma mudança e a atualização nunca chega. setSearchParams dispara uma navegação em vez disso: serializa o que você retorna em uma nova localização e faz push, sem nenhuma comparação de identidade para derrotar.

O que o callback recebe

Desde React Router 7.7.0 você obtém uma cópia dos parâmetros atuais; versões anteriores voltando a 6.4, onde o formulário callback chegou, te entregam a instância ao vivo com que o componente está renderizando. Mutar o que você recebe e retorná-lo funciona em qualquer caso.

A analogia useState também para no queueing: duas chamadas setSearchParams no mesmo handler ambas começam da URL atual, então a segunda sobrescreve a primeira. Defina vários parâmetros em uma chamada em vez disso. Cada set, como cada clique de Link, faz push de uma entrada de histórico por padrão, então para parâmetros que mudam a cada digitação passe { replace: true } como o segundo argumento do setter.

Duas arestas mais afiadas aparecem na prática. Primeiro, uma query string pode legalmente repetir uma chave: ?type=jedi&type=sith. .get retorna apenas o primeiro valor, .getAll retorna todos como um array, e .delete(key) remove toda entrada para aquela chave, então os helpers de mescla acima colapsam chaves repetidas em vez de gerenciá-las individualmente. Filtros de multi-seleção precisam de .getAll mais .append, e .delete(key, value) remove um único valor deixando as outras entradas para aquela chave sozinhas.

Segundo, resista a espelhar parâmetros em estado. Copiar searchParams.get('type') em useState via um efeito cria duas fontes de verdade que saem de sincronização para um render; derivar durante render, como cada exemplo aqui faz, mantém a URL como a única autoridade e custa uma recomputação barata.

JunoA URL pode guardar seu estado Algum estado merece sobreviver a um refresh e viajar em um link compartilhado, como qual filtro está ligado. Parâmetros de busca guardam aquele estado na URL após o ponto de interrogação, e useSearchParams permite você lê-lo: searchParams.get('type') retorna o valor, ou null quando o parâmetro não está lá.

Você pode definir parâmetros com um Link para uma query string ou com a função setter, então filtrar sua lista pelo que a URL diz.

JunoA URL pode guardar seu estado Use o teste de compartilhamento: se revisitar o link deve reproduzir a visualização, o estado pertence a um parâmetro de busca.

Leia-o com useSearchParams, derive a lista filtrada no topo do componente, e defina parâmetros com um Link para escolhas visíveis fixas ou o setter para mudanças programáticas.

Hard-codar uma query string completa apaga parâmetros não relacionados, então mescle: construa a string do Link a partir de uma cópia dos parâmetros atuais, ou use o formulário callback do setter e ajuste a chave que você possui.

JunoA URL pode guardar seu estadosetSearchParams é uma navegação em vez de uma atualização de estado, o que é por que mutar o URLSearchParams anterior no callback é seguro e por que cada set faz push de uma entrada de histórico a menos que você passe replace: true.

Lembre que chaves podem repetir, .get lê apenas a primeira e .delete remove todas, e mantenha a URL como a autoridade única derivando durante render em vez de espelhar parâmetros em estado.

Próximo: Rotas protegidas, onde um ramo do app pergunta quem você é primeiro.