How to Use React Router useSearchParams to Manage Query Parameters in v6
React Router v6's useSearchParams hook returns a tuple containing a URLSearchParams instance and a setter function, enabling components to read and update URL query parameters without triggering full page reloads.
While examining the facebook/react repository, it is essential to recognize that routing functionality resides in the separate React Router ecosystem. The useSearchParams hook, distributed via the react-router-dom package, provides a synchronized interface to the browser's query string, allowing React components to consume and modify URL state declaratively. This implementation leverages React Router's internal navigation context to ensure UI components re-render whenever search parameters change.
Understanding the useSearchParams API
The useSearchParams hook follows a pattern similar to React's useState, but specifically for URL search parameters. When invoked inside a component rendered within a Router, it returns:
const [searchParams, setSearchParams] = useSearchParams();
The searchParams object is an immutable URLSearchParams instance reflecting the current location.search value. The setSearchParams function accepts three types of arguments:
- A new
URLSearchParamsobject - A plain JavaScript object containing key-value pairs
- A function that receives the current
URLSearchParamsand returns a new one
By default, calling setSearchParams pushes a new entry onto the browser's history stack. You can alter this behavior by passing { replace: true } as a second argument, which replaces the current history entry instead.
Reading Query Parameters with useSearchParams
To access individual values from the query string, use the standard URLSearchParams methods on the returned object. The most common method is get(), which retrieves the first value associated with a given key.
import { useSearchParams } from "react-router-dom";
function ProductFilter() {
const [searchParams] = useSearchParams();
// Read specific parameters with fallback values
const category = searchParams.get("category") ?? "all";
const sortOrder = searchParams.get("sort") ?? "ascending";
const page = parseInt(searchParams.get("page") ?? "1", 10);
return (
<div>
<p>Current Category: {category}</p>
<p>Sort: {sortOrder}</p>
<p>Page: {page}</p>
</div>
);
}
For boolean-like parameters, check for existence using has(), or handle multiple values with getAll() when the same key appears multiple times in the query string.
Updating URL Search Parameters
Replacing All Parameters
To completely reset the query string, pass a plain object or new URLSearchParams instance to the setter. This removes any existing parameters not included in the new object.
const [searchParams, setSearchParams] = useSearchParams();
// Clear all filters and set only category
const setCategoryOnly = (newCategory: string) => {
setSearchParams({ category: newCategory });
};
Modifying Specific Parameters
Typically, you want to update one parameter while preserving others. Create a mutable copy of the current searchParams using the constructor, then modify it.
const updateFilter = (key: string, value: string) => {
const nextParams = new URLSearchParams(searchParams);
nextParams.set(key, value);
setSearchParams(nextParams);
};
Functional Updates
When the new state depends on the previous state, pass a function to setSearchParams. This ensures you operate on the most current parameters, avoiding stale closure issues in rapid update scenarios.
const incrementPage = () => {
setSearchParams((prev) => {
const currentPage = parseInt(prev.get("page") ?? "1", 10);
prev.set("page", String(currentPage + 1));
return prev;
});
};
Using Replace vs Push
Prevent polluting the browser history when updating transient UI state (like search filters) by using the replace option.
// Replace current history entry instead of pushing new one
setSearchParams({ search: query }, { replace: true });
According to the React Router source code in packages/react-router-dom/index.tsx, the setSearchParams implementation wraps the useNavigate hook to perform these history mutations, while packages/react-router/dom.ts contains the underlying navigation logic that handles the replace flag.
Complete Working Example
The following component demonstrates reading, updating, and clearing query parameters in a product listing interface:
import { useSearchParams } from "react-router-dom";
function ProductList() {
// 1️⃣ Obtain the current query parameters and the setter
const [searchParams, setSearchParams] = useSearchParams();
// 2️⃣ Read a specific parameter (e.g., ?category=books)
const category = searchParams.get("category") ?? "all";
// 3️⃣ Update a parameter while preserving the others
const changeCategory = (newCat: string) => {
// Create a copy, modify it, then push the new URL
const next = new URLSearchParams(searchParams);
next.set("category", newCat);
setSearchParams(next);
};
// 4️⃣ Remove a parameter (e.g., clearing a filter)
const clearSearch = () => {
// Passing an empty object removes all query params
setSearchParams({});
};
return (
<div>
<h2>Products – Category: {category}</h2>
{/* Buttons to demonstrate updates */}
<button onClick={() => changeCategory("books")}>Books</button>
<button onClick={() => changeCategory("electronics")}>Electronics</button>
<button onClick={clearSearch}>Clear Filters</button>
{/* Render filtered product list based on `category` … */}
</div>
);
}
Implementation Architecture
Although you are examining the facebook/react repository, the useSearchParams implementation resides in the React Router codebase at remix-run/react-router. The hook is defined in packages/react-router-dom/index.tsx, where it composes useNavigate and useLocation from the core router packages. The actual history manipulation relies on the navigation logic in packages/react-router/dom.ts, while the location state management derives from packages/react-router/history.ts. This architecture ensures that any parameter changes flow through React Router's centralized history management, triggering re-renders only for components subscribed to the relevant route context.
Summary
useSearchParamsreturns a tuple of[URLSearchParams, setter]for reading and writing query parameters in React Router v6 applications.- The setter function accepts objects,
URLSearchParamsinstances, or functional updates, providing flexibility for different state management patterns. - Always create a copy of
searchParamsbefore mutating to preserve existing query parameters when updating individual values. - Use the
{ replace: true }option to update the URL without creating new browser history entries for transient state changes. - The implementation lives in the
react-router-dompackage, specifically utilizing logic frompackages/react-router-dom/index.tsxandpackages/react-router/dom.ts.
Frequently Asked Questions
How do I access multiple values for the same query parameter key?
Use the getAll() method on the searchParams object returned by useSearchParams. For example, if your URL contains ?tag=react&tag=router, calling searchParams.getAll("tag") returns an array ["react", "router"]. This is useful for handling multi-select filters or arrays encoded in the query string.
Can I use useSearchParams outside of a Router component?
No. The useSearchParams hook relies on React Router's navigation context, which is provided by BrowserRouter, HashRouter, or MemoryRouter. Attempting to use the hook outside of any Router provider will throw a context error. Ensure your component tree is wrapped in a Router component from react-router-dom before calling this hook.
What is the difference between useSearchParams and the native URLSearchParams API?
While useSearchParams returns a standard URLSearchParams instance for reading, its setter function (setSearchParams) is React Router's abstraction over the browser's history API. Unlike manual window.location.search updates, setSearchParams integrates with React Router's routing system, triggering component re-renders and respecting the router's basename or future configuration options defined in packages/react-router/history.ts.
How do I remove a specific query parameter while keeping others?
Create a new URLSearchParams instance from the current one, call the delete() method on the specific key, then pass the modified object to setSearchParams. For example: const next = new URLSearchParams(searchParams); next.delete("filter"); setSearchParams(next);. This preserves all other query parameters intact.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →