Search Params
Leia e manipule parâmetros de consulta de URL com useSearchParams (cliente) e a prop searchParams (servidor).
Busque em todas as páginas da documentação
Leia e manipule parâmetros de consulta de URL com useSearchParams (cliente) e a prop searchParams (servidor).
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Cartão de receita de referência rápida -- pronto para copiar e colar.
// Componente de Servidor -- acesse searchParams como uma prop (Promise no Next.js 15+)
type Props = { searchParams: Promise<{ q?: string; page?: string }> };
export default async function Page({ searchParams }: Props) {
const { q, page } = await searchParams;
const results = await search(q, Number(page) || 1);
return <ResultsList results={results} />;
}// Componente Cliente -- hook useSearchParams
"use client";
import { useSearchParams, useRouter, usePathname } from "next/navigation";
export function SearchInput() {
const searchParams = useSearchParams();
const router = useRouter();
const pathname = usePathname();
function handleSearch(term: string) {
const params = new URLSearchParams(searchParams.toString());
if (term) params.set("q", term);
else params.delete("q");
router.push(`${pathname}?${params.toString()}`);
}
return (
<input
defaultValue={searchParams.get("q") ?? ""}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search..."
/>
);
}Quando usar isso: Você precisa de estado controlado pela URL -- filtros de pesquisa, paginação, ordenação -- que deve ser compartilhável via URL e sobreviver a atualizações de página.
// app/products/page.tsx (Componente de Servidor)
import { Suspense } from "react";
import { SearchBar } from "./search-bar";
import { ProductGrid } from "./product-grid";
import { Pagination } from "./pagination";
type Props = {
searchParams: Promise<{
q?: string;
category?: string;
sort?: string;
page?: string;
}>;
};
export default async function ProductsPage({ searchParams }: Props) {
const { q, category, sort, page } = await searchParams;
return (
<main className="max-w-6xl mx-auto p-6">
<h1 className="text-2xl font-bold mb-6">Produtos</h1>
<Suspense fallback={<div>Carregando pesquisa...</div>}>
<SearchBar />
</Suspense>
<Suspense
key={`${q}-${category}-${sort}-${page}`}
fallback={<div>Carregando produtos...</div>}
>
<ProductResults
query={q}
category={category}
sort={sort ?? "newest"}
page={Number(page) || 1}
/>
</Suspense>
</main>
);
}
async function ProductResults({
query,
category,
sort,
page,
}: {
query?: string;
category?: string;
sort: string;
page: number;
}) {
const { products, totalPages } = await fetchProducts({
query,
category,
sort,
page,
});
return (
<>
<ProductGrid products={products} />
<Pagination currentPage={page} totalPages={totalPages} />
</>
);
}// app/products/search-bar.tsx
"use client";
import { useSearchParams, usePathname, useRouter } from "next/navigation";
import { useTransition } from "react";
import { useDebouncedCallback } from "use-debounce";
export function SearchBar() {
const searchParams = useSearchParams();
const pathname = usePathname();
const router = useRouter();
const [isPending, startTransition] = useTransition();
const handleSearch = useDebouncedCallback((term: string) => {
const params = new URLSearchParams(searchParams.toString());
if (term) {
params.set("q", term);
params.set("page", "1"); // reseta para a página 1 em nova pesquisa
} else {
params.delete("q");
}
startTransition(() => {
router.push(`${pathname}?${params.toString()}`);
});
}, 300);
return (
<div className="relative mb-6">
<input
type="search"
defaultValue={searchParams.get("q") ?? ""}
onChange={(e) => handleSearch(e.target.value)}
placeholder="Search products..."
className="w-full border rounded px-4 py-2"
/>
{isPending && (
<span className="absolute right-3 top-2.5 text-gray-400">
Searching...
</span>
)}
</div>
);
}// app/products/pagination.tsx
"use client";
import { useSearchParams, usePathname } from "next/navigation";
import Link from "next/link";
export function Pagination({
currentPage,
totalPages,
}: {
currentPage: number;
totalPages: number;
}) {
const searchParams = useSearchParams();
const pathname = usePathname();
function createPageUrl(page: number) {
const params = new URLSearchParams(searchParams.toString());
params.set("page", page.toString());
return `${pathname}?${params.toString()}`;
}
return (
<div className="flex gap-2 mt-6">
{currentPage > 1 && (
<Link href={createPageUrl(currentPage - 1)} className="px-3 py-1 border rounded">
Previous
</Link>
)}
<span className="px-3 py-1">
Page {currentPage} of {totalPages}
</span>
{currentPage < totalPages && (
<Link href={createPageUrl(currentPage + 1)} className="px-3 py-1 border rounded">
Next
</Link>
)}
</div>
);
}O que isso demonstra:
searchParams no servidor como uma Promise (padrão Next.js 15+)useSearchParams no cliente para ler e atualizar parâmetros de consultakey em <Suspense> para reativar estados de carregamento em mudanças de parâmetrosearchParams no lado do servidor: No App Router, os componentes de página recebem searchParams como uma prop. No Next.js 15+, isso é uma Promise que deve ser aguardada. Acessar searchParams opta a rota para renderização dinâmica.useSearchParams no lado do cliente: Retorna uma instância URLSearchParams somente leitura. Para atualizar, construa um novo URLSearchParams, modifique-o e navegue com router.push() ou router.replace().useSearchParams requer um limite Suspense -- Durante o pré-renderização estática, os parâmetros de pesquisa não estão disponíveis. Envolver o componente em <Suspense> fornece um fallback enquanto os parâmetros são hidratados no cliente.router.push cria uma nova entrada de histórico; router.replace substitui a entrada atual (melhor para filtros e ordenação).Usando router.replace para evitar poluir o histórico:
// Bom para filtros -- o usuário ainda pode usar o botão voltar de forma significativa
startTransition(() => {
router.replace(`${pathname}?${params.toString()}`);
});Lendo um único parâmetro com um padrão:
const sort = searchParams.get("sort") ?? "newest";
const page = Number(searchParams.get("page")) || 1;Parâmetros de múltiplos valores (arrays):
// URL: ?color=red&color=blue
const colors = searchParams.getAll("color"); // ["red", "blue"]
// Definindo múltiplos valores
const params = new URLSearchParams();
["red", "blue"].forEach((c) => params.append("color", c));// Tipo searchParams do componente de servidor (Next.js 15+)
type PageProps = {
params: Promise<{ slug: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }>;
};
// Helper de search params tipado
type ProductFilters = {
q?: string;
category?: string;
sort?: "newest" | "price-asc" | "price-desc";
page?: string;
};
type Props = { searchParams: Promise<ProductFilters> };searchParams opta a rota para renderização dinâmica -- Qualquer página que leia searchParams no servidor não pode ser gerada estaticamente. Correção: Se você deseja uma página estática com filtragem no lado do cliente, leia os parâmetros apenas em Componentes Cliente com useSearchParams.
useSearchParams sem Suspense causa erros de compilação -- Durante a pré-renderização, useSearchParams lança um erro porque não há parâmetros para ler. Correção: Sempre envolva componentes que usam useSearchParams em um limite <Suspense>.
Closure obsoleto com searchParams -- Em um Componente Cliente, a referência searchParams de useSearchParams() atualiza na navegação, mas closures em manipuladores de eventos podem capturar o valor antigo. Correção: Leia searchParams no momento da chamada dentro do manipulador, não fora dele.
Parâmetros de array perdem segurança de tipo -- searchParams.get("color") retorna apenas o primeiro valor, mesmo quando múltiplos existem. Correção: Use searchParams.getAll("color") para parâmetros de múltiplos valores.
searchParams é uma Promise no Next.js 15+ -- Desestruturá-lo diretamente sem await retorna um objeto Promise. Correção: Sempre use const { q } = await searchParams em Componentes de Servidor.
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
useState (apenas cliente) | O estado é efêmero e não precisa sobreviver à atualização | O estado deve ser compartilhável via URL |
Segmentos de rota dinâmicos ([slug]) | O parâmetro define a identidade do recurso | O parâmetro é um filtro ou modificador |
| Cookies | O estado deve persistir entre sessões, mas não aparecer na URL | O estado deve ser visível e compartilhável |
Biblioteca nuqs | Você deseja parâmetros de pesquisa tipados e validados com serialização | useSearchParams integrado é suficiente |
| Zustand com sincronização de URL | Estado complexo com múltiplos parâmetros e valores derivados | Parâmetros de URL simples chave-valor |
searchParams é uma Promise que deve ser aguardada antes de acessar as propriedadesawait retorna um objeto Promise, não os valoressearchParams em um Componente de Servidor opta a rota para renderização dinâmicauseSearchParams<Suspense>, a compilação falha porque useSearchParams lança um errorouter.push cria uma nova entrada no histórico do navegador (o usuário pode pressionar voltar)router.replace substitui a entrada atual do histórico (melhor para filtros e ordenação)replace quando mudanças frequentes de parâmetros poluiriam a pilha de histórico// Lendo múltiplos valores
const colors = searchParams.getAll("color"); // ["red", "blue"]
// Definindo múltiplos valores
const params = new URLSearchParams();
["red", "blue"].forEach((c) => params.append("color", c));searchParams.get("color") retorna apenas o primeiro valorconst handleSearch = (term: string) => {
const params = new URLSearchParams(searchParams.toString());
if (term) {
params.set("q", term);
params.set("page", "1"); // reseta para a página 1
} else {
params.delete("q");
}
router.push(`${pathname}?${params.toString()}`);
};type PageProps = {
params: Promise<{ slug: string }>;
searchParams: Promise<{
[key: string]: string | string[] | undefined;
}>;
};string, string[] ou undefinedsearchParams antigasearchParams atualiza na navegação, mas o closure não o captura novamentesearchParams no momento da chamada dentro do manipulador para obter o valor mais recente<Suspense
key={`${q}-${category}-${sort}-${page}`}
fallback={<div>Loading...</div>}
>
<ProductResults query={q} sort={sort} page={page} />
</Suspense>key desmonta e remonta o limite do Suspense, mostrando o fallback novamente[slug]) quando o parâmetro define a identidade do recurso (ex: /products/shoes)searchParams quando o parâmetro é um filtro ou modificador (ex: ?sort=price&page=2)type ProductFilters = {
q?: string;
category?: string;
sort?: "newest" | "price-asc" | "price-desc";
page?: string;
};
type Props = { searchParams: Promise<ProductFilters> };useSearchParams resideRevisado por Chris St. John·Última atualização: 16 de jul. de 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥