GioJSdocs
On this page

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 it

The 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=b gives getAll('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.search in 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, getServerSideProps reads the same values as ctx.query, and a route handler as req.query.

Version history

VersionChanges
v0.1.0-beta.8Introduced.