useQueryParams
A reactive URLSearchParams interface that allows you to get, set, and delete query parameters in the URL. Under the hood this proxies Next.js’s useSearchParams hook with additional URL manipulation methods.
Anatomy
type QueryParamsOptions = { replace?: boolean; // default {false} shallow?: boolean; // default {true}};declare function useQueryParams(options?: QueryParamsOptions): URLSearchParams;Usage
import { useQueryParams } from "@frend-digital/ui/next";
const UnsuspendedComponent = () => { const searchParams = useQueryParams();
const nameIsBob = searchParams.has("name", "bob");
return ( <button onClick={() => searchParams.set("name", "bob")}> {searchParams.get("name")} </button> );};
export const Component = () => { return ( <Suspense> <UnsuspendedComponent /> </Suspense> );};Non-shallow routing
By default the useSearchParams hook will perform a shallow router push, meaning the URL changes, but the page is not reloaded. This is useful when you only care about the query state on the client side and have to need to reload server components depending on the query state.
To make a full router push, you need to pass shallow: false to the hook.
const UnsuspendedProductFilter = () => { const searchParams = useQueryParams({ shallow: false });
return ( <button onClick={() => searchParams.has("category", "clothing") ? searchParams.delete("category", "clothing") : searchParams.set("category", "clothing") } > Filter by Clothing </button> );};
export const ProductFilter: typeof UnsuspendedProductFilter = () => { return ( <Suspense> <UnsuspendedProductFilter /> </Suspense> );};In your server component, consume the searchParams
const Page = async ({ searchParams }) => { const category = searchParams.category;
const params = new URLSearchParams(); if (category) { params.set("category", category); }
const res = await fetch(`/api/products?${params.toString()}`);
const products = await res.json();
return ( <> <ProductFilter /> <ProductList products={products} /> </> );};Your page will now load new data when the filter is toggled.
Replace & Push
By default the useQueryParams hook performs a router push, meaning a new entry is pushed onto the history stack, and the user can navigate back and remove the query.
If you want to replace the current entry in the history stack, you can pass replace: true to the hook.
const UnsuspendedProductFilter = () => { const searchParams = useQueryParams({ replace: true }); return ( <button onClick={() => searchParams.has("category", "clothing") ? searchParams.delete("category", "clothing") : searchParams.set("category", "clothing") } > Filter by Clothing </button> );};This will replace the current entry in the history stack, and the user can no longer navigate back to the previous query.