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

Parámetros de búsqueda

Los parámetros de ruta le indican a tu app en qué página estás. Los parámetros de búsqueda, también llamados parámetros de consulta, describen cómo debería verse esa página: qué filtro está activo, por qué está ordenada la lista, qué página de resultados se muestra. Viven en la URL después de un signo de interrogación, como pares clave/valor como /vans?type=rugged, con pares adicionales unidos por ampersands: /vans?type=rugged&sort=price. Como forman parte de la URL, sobreviven a una recarga y viajan dentro de un enlace compartido, lo que los hace un tipo de estado diferente a cualquier cosa que useState pueda sostener.

Estado que pertenece a la URL

El estado guardado con useState vive en memoria. Recarga la página y se reinicia a su valor inicial; copia la URL a un amigo y obtendrá un comienzo fresco sin ninguna de tus opciones. Para mucho estado eso es exactamente lo correcto. Para algunas cosas, es una pérdida real: si has reducido una lista de vans a solo las robustas por debajo de cierto precio, probablemente quieras que una recarga mantenga esa vista, y quieras que un enlace pegado abra la misma lista curada para otra persona.

El curso ofrece una prueba útil: ¿debería un usuario poder revisitar o compartir esta página exactamente como está y obtener el mismo resultado? Si es sí, considera extraer ese estado de React y llevarlo a la URL como parámetro de búsqueda. Filtrar, ordenar y paginar son los candidatos clásicos. La URL se convierte entonces en la única fuente de verdad para ese estado, y tu componente deriva lo que renderiza de ella, de la misma manera que lo haría de estado o props.

Leer parámetros con useSearchParams

React Router expone la cadena de consulta a través del hook useSearchParams, y su forma es deliberadamente cercana a useState: un array que contiene el valor actual y un setter.

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

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

searchParams es una instancia del objeto nativo del navegador URLSearchParams en lugar de un objeto plano, así que interactúas con él a través de sus métodos. .get('type') devuelve el valor del parámetro type como string, y devuelve null cuando ese parámetro no está en la URL en absoluto. Ese null es cómo tu código sabe que ningún filtro está activo. .toString() serializa el conjunto completo de vuelta a una cadena de consulta como type=sith&sort=price, sin el signo de interrogación inicial.

Nota de versión

Los ejemplos aquí importan de react-router-dom, que funciona en v6 y v7; Routing cubre qué cambió en v7 sobre los paquetes.

Filtrar una lista desde un parámetro

Con el parámetro en mano, filtrar es JavaScript plano en la parte superior del componente. Sin estado, sin efecto: leer un parámetro y filtrar un array son ambas operaciones rápidas, así que está bien rehacer el trabajo en cada renderizado y dejar que el resultado salga de la 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>
))

El ternario maneja el caso sin filtro: cuando .get devuelve null, se muestra la lista completa. Elegir qué array renderizar de esta forma es el mismo movimiento derive-as-you-render que has usado para renderizado condicional, impulsado por la URL en lugar de por estado. También vigila los desajustes de mayúsculas; los datos almacenan "Sith" mientras que un enlace editado manualmente podría llevar Sith o sith, así que ambos lados se convierten a minúsculas antes de ser comparados.

La forma más directa de poner un parámetro de búsqueda en la URL es un Link cuyo to comienza con un signo de interrogación. React Router ve el ? inicial, te mantiene en la ruta actual, e intercambia la nueva cadena de consulta, lo que re-renderiza el componente y re-ejecuta tu filtrado.

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

Para limpiar, to="." navega a la ruta actual sin consulta adjunta; to="" también funciona, y el curso se establece en el punto como el más explícito de los dos. Los Links funcionan mejor cuando el filtro es un conjunto fijo de opciones visibles: se renderizados como etiquetas de ancla reales, así que los usuarios pueden abrir una vista filtrada en una pestaña nueva o copiar la dirección antes de hacer clic.

Establecer parámetros con la función setter

El segundo elemento de useSearchParams es un setter, y como el de useState acepta un valor de reemplazo o un callback. Como un botón no es parte del ecosistema de React Router de la forma que Link es, llamas al setter desde un manejador de eventos ordinario.

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

El setter es flexible sobre lo que toma: un string como '?type=jedi' (con o sin el signo de interrogación) funciona, pero la forma de objeto mostrada aquí es lo que verás más a menudo, y un objeto vacío limpia todo. Recurre al setter cuando los nuevos parámetros salen de lógica en lugar de un clic en una opción fija: leer valores de un formulario, responder a la entrada mientras el usuario escribe, o establecer varios parámetros a la vez.

Reemplazar borra los otros parámetros

Ambos enfoques hasta ahora codifican la cadena de consulta completa. Eso está bien mientras type sea el único parámetro que tu app usa, pero en el momento en que la URL también lleve algo no relacionado, digamos ?name=jill&type=jedi, hacer clic en uno de esos enlaces o botones reemplaza la cadena de consulta completa y name=jill se va. Los botones de limpiar son aún más contundentes: borran cada parámetro en la URL, incluyendo aquellos que este componente nunca tocó. Si estás seguro de que tu proyecto solo tendrá el parámetro único, la codificación dura está bien. De lo contrario quieres combinar.

Combinar con parámetros existentes

Para Links, la prop to toma un string, así que la solución es un pequeño helper que se ejecuta durante el renderizado: copia los parámetros actuales a un URLSearchParams fresco, cambia la única clave que se mueve, y serializa el resultado. Vive dentro del componente, ya que lee searchParams del hook.

jsx
// inside CharacterList, so it can read 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)}>Clear</Link>

Esto es JavaScript vanilla en lugar de cualquier cosa que React Router proporcione. El constructor URLSearchParams acepta felizmente un objeto de parámetros existente como punto de partida, .set actualiza o agrega una clave, y pasar null le indica al helper que .delete la clave en lugar, así que "Clear" ahora solo elimina type y deja todo lo demás en la URL intacto.

Para el setter, usa su forma de callback. El callback recibe el objeto de parámetros anterior, ajustas la única clave, y lo devuelves.

jsx
// inside CharacterList, so it can call 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)}>Clear</button>

Una sorpresa que el curso señala: a diferencia de un actualizador useState, donde mutar el estado anterior está prohibido, aquí está bien llamar a .delete y .set directamente en prevParams y devolverlo. Ahora tanto los enlaces como los botones cambian solo el parámetro que poseen.

La mutación siendo segura es consecuencia de lo que el setter realmente hace. Cuando despachas una actualización useState, React compara el nuevo valor con el actual con Object.is antes de programar un re-renderizado, así que devolver el mismo objeto mutado se lee como sin cambio y la actualización nunca llega. setSearchParams desencadena una navegación en lugar: serializa lo que sea que devuelvas en una nueva ubicación y la empuja, sin comparación de identidad para derrotarla.

Qué recibe el callback

Desde React Router 7.7.0 obtienes una copia de los parámetros actuales; versiones anteriores que se remontan a 6.4, donde llegó la forma de callback, te entregan la instancia viva con la que el componente está renderizando. Mutar lo que te dan y devolverlo funciona en ambos casos.

La analogía useState también se detiene en queueing: dos llamadas setSearchParams en el mismo manejador comienzan ambas desde la URL actual, así que la segunda sobrescribe la primera. Establece varios parámetros en una llamada en lugar. Cada set, como cada clic Link, empuja una entrada de historial por defecto, así que para parámetros que cambian en cada pulsación de tecla pasa { replace: true } como el segundo argumento del setter.

Dos bordes más afilados se muestran en la práctica. Primero, una cadena de consulta puede legalmente repetir una clave: ?type=jedi&type=sith. .get devuelve solo el primer valor, .getAll devuelve todos como un array, y .delete(key) elimina cada entrada para esa clave, así que los helpers de combinación anterior colapsan claves repetidas en lugar de gestionarlas individualmente. Los filtros multi-select necesitan .getAll más .append, y .delete(key, value) elimina un único valor mientras deja las otras entradas para esa clave solas.

Segundo, evita espejear parámetros en estado. Copiar searchParams.get('type') a useState vía un efecto crea dos fuentes de verdad que se desincronizar durante un renderizado; derivar durante el renderizado, como cada ejemplo aquí hace, mantiene la URL como la única autoridad y cuesta una recomputación económica.

JunoLa URL puede sostener tu estado Algún estado merece sobrevivir a una recarga y viajar en un enlace compartido, como qué filtro está activado. Los parámetros de búsqueda mantienen ese estado en la URL después del signo de interrogación, y useSearchParams te permite leerlo: searchParams.get('type') devuelve el valor, o null cuando el parámetro no está ahí.

Puedes establecer parámetros con un Link a una cadena de consulta o con la función setter, luego filtrar tu lista de lo que sea que la URL diga.

JunoLa URL puede sostener tu estado Usa la prueba de compartir: si revisitar el enlace debe reproducir la vista, el estado pertenece a un parámetro de búsqueda.

Léelo con useSearchParams, deriva la lista filtrada en la parte superior del componente, y establece parámetros con un Link para opciones visibles fijas o el setter para cambios programáticos.

Codificar una cadena de consulta completa borra parámetros no relacionados, así que combina: construye la cadena Link desde una copia de los parámetros actuales, o usa la forma de callback del setter y ajusta la única clave que posees.

JunoLa URL puede sostener tu estadosetSearchParams es una navegación en lugar de una actualización de estado, que es por qué mutar el URLSearchParams anterior en el callback es seguro y por qué cada set empuja una entrada de historial a menos que pases replace: true.

Recuerda que las claves pueden repetirse, .get lee solo la primera y .delete las elimina todas, y mantén la URL como la única autoridad derivando durante el renderizado en lugar de espejear parámetros en estado.

Próximo: Rutas protegidas, donde una rama de la app primero te pregunta quién eres.