How to Read and Update Search Params in React Router

Read and update URL search params in React Router with the useSearchParams hook. Build tabs, filters, and shareable URLs.

5 min read

React Router search params are the values after the question mark in a URL, like ?q=react. The useSearchParams hook reads and updates them, which makes filters and tabs shareable through the address bar. Unlike route params in the path, search params are optional and unordered.

Read a search param

Call useSearchParams to get a URLSearchParams instance and a setter function. Use the get method on that instance to read a single value.

App.jsxApp.jsx
import { useSearchParams } from "react-router";
 
export default function Search() {
  const [searchParams] = useSearchParams();
  const query = searchParams.get("q");
  return <p>Results for {query}</p>;
}

For the URL /search?q=router, query is the string "router". A missing param returns null, so give the page a fallback value instead of rendering a blank label.

You can also pass a default value to useSearchParams, which applies when the URL has no search string.

Read several params at once

A filter page usually reads more than one value. Call get for each param you care about, with a fallback for the ones that can be missing.

App.jsxApp.jsx
import { useSearchParams } from "react-router";
 
export default function Products() {
  const [searchParams] = useSearchParams();
  const category = searchParams.get("category") || "all";
  const sort = searchParams.get("sort") || "new";
  return <p>Showing {category}, sorted by {sort}</p>;
}

The fallbacks keep the page meaningful on a plain /products URL with no query string.

On /products?category=books&sort=old, the component shows both values.

Update search params

The setter accepts a string, an object, an array, or a function. Calling it navigates to a new URL with the updated query string.

App.jsxApp.jsx
function TabLinks() {
  const [, setSearchParams] = useSearchParams();
  return (
    <nav>
      <button onClick={() => setSearchParams({ tab: "one" })}>One</button>
      <button onClick={() => setSearchParams({ tab: "two" })}>Two</button>
    </nav>
  );
}

Clicking Two changes the URL to end in ?tab=two. The object form replaces the query string with the keys you pass.

A raw string works too, so passing ?tab=two produces the same URL.

To change one key while keeping the rest, use the function form and mutate the current URLSearchParams.

App.jsxApp.jsx
setSearchParams((searchParams) => {
  searchParams.set("tab", "two");
  return searchParams;
});

This keeps any other params like ?q intact while switching the tab. The function form does not queue like React state, so call it once per change.

Why search params beat component state

Filters and tabs often live in component state, but the URL has three advantages:

  • A copied link carries the filter with it.
  • The back button moves through filter changes as history entries.
  • A reload restores the exact view the user was on.

Loaders can also read search params from the request, which React Router loaders and actions explained covers. For required values, route params in the path fit better, covered in dynamic routes and URL parameters.

Keep sensitive values out of the query string, because the URL is logged and shared.

Common mistakes

  • Reading a missing param without a fallback.
  • Assuming setSearchParams merges when it actually replaces.
  • Calling the function setter twice expecting queued updates.
  • Treating search params as the source of truth for data that should come from a loader.
Rune AI

Rune AI

Key Insights

  • Read a value with searchParams.get from useSearchParams.
  • Update the URL by calling setSearchParams with a string or object.
  • Use the function form to change one key without dropping the rest.
  • Search params keep filters and tabs shareable through the URL.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between params and search params?

Route params live in the path, like /teams/:teamId. Search params live after the question mark, like ?q=react, and are usually optional filters or state.

Does setSearchParams merge with existing params?

No. The object form replaces the query string. Use the function form and set one key when you need to keep the other params.

Can I read search params in a loader?

Yes. The loader receives a request, and new URL(request.url).searchParams reads the current values.

Conclusion

Search params hold the values after the ? in a URL. Read them with useSearchParams and update them with setSearchParams, which navigates to a new URL. Use the function form to change one key while keeping the rest.