useSearchParams
Read the current page's query string as a read-only URLSearchParams.
tsx
import { useSearchParams } from '@gio.js/react';
export function SortLabel() {
const searchParams = useSearchParams();
const sort = searchParams.get('sort') ?? 'newest'; // /products?sort=price -> 'price'
return <span>Sorted by {sort}</span>;
}Reference
Parameters
useSearchParams takes no parameters.
Returns
A ReadonlyURLSearchParams: a URLSearchParams whose reading methods all work - get, getAll, has, keys, entries, forEach, toString, size and iteration - and whose set, append, delete and sort throw:
text
Error: useSearchParams() is read-only: build a new URLSearchParams(searchParams) and navigate to itThe object is created again only when the query changes, so it is stable across renders of the same page and safe in effect dependencies.
Behavior
- The query is the one the server rendered the page for, carried into the browser with the page, so server and hydration renders agree. After a soft navigation it is the new page's query.
- Each key has one value, the last one in the URL:
?tag=a&tag=bgivesgetAll('tag')=['b']. The order of the keys is not kept either. - Outside a tree GioJS rendered (a unit test), it reads
window.location.search, or nothing on the server.
Examples
Updating the query
Copy the params, change the copy, and navigate. replace keeps one history entry, and scroll: false keeps the position.
app/products/sort-select.tsx
import type { ChangeEvent } from 'react';
import { usePathname, useRouter, useSearchParams } from '@gio.js/react';
export function SortSelect() {
const router = useRouter();
const pathname = usePathname();
const searchParams = useSearchParams();
function onChange(event: ChangeEvent<HTMLSelectElement>) {
const next = new URLSearchParams(searchParams.toString());
next.set('sort', event.target.value);
next.delete('page');
void router.replace(`${pathname}?${next}`, { scroll: false });
}
return (
<select value={searchParams.get('sort') ?? 'newest'} onChange={onChange}>
<option value="newest">Newest</option>
<option value="price">Price</option>
</select>
);
}Search as you type
A navigation that only changes the query keeps focus in the field that still exists, so the visitor keeps typing.
app/search/search-box.tsx
import { useRouter, useSearchParams } from '@gio.js/react';
export function SearchBox() {
const router = useRouter();
const q = useSearchParams().get('q') ?? '';
return (
<input
type="search"
defaultValue={q}
onChange={(event) => void router.replace('/search?q=' + encodeURIComponent(event.target.value), { scroll: false })}
/>
);
}Good to know
- Repeated keys keep only the last value. The server parses the query into one value per key before the page renders, so
getAll()returns at most one item. For lists, use one key with a separator (?tags=a,b). - In a static export the query is always empty. Pages are rendered once, without a query, and the browser reads the value the HTML was built with. Read
window.location.searchin an effect there. - On a page cached with
revalidate, each distinct query string is rendered and cached as its own entry, so a query a visitor can vary freely multiplies the cache entries. - In the server-only root layout the value is that of the page loaded in full.
- On the server,
getServerSidePropsreads the same values asctx.query, and a route handler asreq.query.
Related
useRouter- change the query by navigating.usePathname,useParams- the rest of the URL.- Focus and announcements - why the search field keeps focus.
getServerSideProps- read the query on the server.
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | Introduced. |