Gathering detailed insights and metrics for use-search-param-state
Gathering detailed insights and metrics for use-search-param-state
a hook to synchronize React state with URL search params.
npm install use-search-param-state
Typescript
Module System
Node Version
NPM Version
TypeScript (95.14%)
JavaScript (3.75%)
Shell (1.11%)
Love this project? Help keep it running — sponsor us today! 🚀
Total Downloads
2,672
Last Day
2
Last Week
5
Last Month
56
Last Year
1,452
3 Stars
98 Commits
1 Watching
2 Branches
1 Contributors
Minified
Minified + Gzipped
Latest Version
2.0.16
Package Id
use-search-param-state@2.0.16
Unpacked Size
30.27 kB
Size
7.68 kB
File Count
7
NPM Version
10.8.1
Node Version
20.14.0
Publised On
09 Jun 2024
Cumulative downloads
Total Downloads
Last day
0%
2
Compared to previous day
Last week
-68.8%
5
Compared to previous week
Last month
51.4%
56
Compared to previous month
Last year
19%
1,452
Compared to previous year
22
A hook to synchronize React state with URL search params.
1import { useSearchParamState } from "use-search-param-state"; 2 3function Root() { 4 return ( 5 <SearchParamStateProvider> 6 <Demo /> 7 </SearchParamStateProvider> 8 ); 9} 10 11function Demo() { 12 const [counterState, setCounterState] = useSearchParamState("counter", 0); 13}
or
1import { useSearchParamState } from "use-search-param-state"; 2import { z } from "zod"; 3 4function Root() { 5 // this `sanitize` is used by every instance of `useSearchParamState` 6 const sanitize = (unsanitized: string) => yourSanitizer(unsanitized); 7 return ( 8 <SearchParamStateProvider buildOptions={{ sanitize }}> 9 <Demo /> 10 </SearchParamStateProvider> 11 ); 12} 13 14function Demo() { 15 const schema = z.number(); 16 const [counterState, setCounterState] = useSearchParamState("counter", 0, { 17 validate: schema.parse, 18 }); 19}
On the first render, useSearchParamState
will read from the counter
URL search param.
By default, the counter
search param is read using window.location.href
. If the window
object is undefined
, useSearchParamState
will use the serverSideURL
instead to read from the URL. If serverSideURL
is also not provided, counterState
will be set to the initial state (i.e. 0
).
If the counter
search param does not exist (i.e. URLSearchParams.get
returns null
), counterState
will be set to the initial state.
Once the counter
search param is accessed, the raw string is passed to sanitize
, the output of sanitize
is passed to parse
, and finally the output of parse
is passed to validate
. Note that useSearchParamState
aims to return a parsed value, not a stringified value!
If sanitize
, parse
, or validate
throw an error, the onError
option is called and counterState
will be set to the initial state.
If none of sanitize
, parse
, and validate
throw an error, counterState
is set to the sanitized, parsed, and validated value in the counter
search param.
Note that
useSearchParamState
intentionally does not set the URL on the first render, since this can cause an infinite loop when navigating backwards. For example, say we have a url/blog
with a search paramsearch
defaulted tohello
. Navigating to/blog
would immediately add?search=hello
to the URL, so navigating backwards would push/blog
... which would add?search=hello
to the URL again!
When setting the state using setCounterState
, the new state is stringified using the stringify
option, and the URL is set using the pushState
option.
If deleteEmptySearchParam
is true
and isEmptySearchParam
returns true
, the search param will be deleted from the URL.
However, if stringify
or pushState
throw an error, onError
will be called and the URL will not be set. Additionally, if the rollbackOnError
option is set to true
, counterState
will be set to its value prior to when setCounterState
was called. Otherwise, counterState
will retain its new value, and the counter
URL search param will be out of sync with counterState
. The latter behavior is the default, since local state tends to take precedence over URL state.
Note that multiple instances of useSearchParamState
that read from the same URL search param will be kept in-sync thanks to the SearchParamStateProvider
wrapping your app.
useSearchParamState
accepts the following options:
1interface UseSearchParamStateOptions<TVal> { 2 stringify?: (valToStringify: TVal) => string; 3 sanitize?: (unsanitized: string) => string; 4 parse?: (unparsed: string) => TVal; 5 validate?: (unvalidated: unknown) => TVal; 6 deleteEmptySearchParam?: boolean; 7 isEmptySearchParam?: (searchParamVal: TVal) => boolean; 8 serverSideURL?: string; 9 rollbackOnError?: boolean; 10 pushState?: (stringifiedSearchParams: string) => void; 11 onError?: (e: unknown) => void; 12}
Note that sanitize
, parse
, and validate
run in the following order when pulling the initial state from the URL search param:
1// simplified 2const rawSearchParam = new URLSearchParams(window.location.search).get( 3 searchParam, 4); 5const sanitized = options.sanitize(rawSearchParam); 6const parsed = options.parse(sanitized); 7const validated = options.validate(parsed); 8 9return validated;
sanitize
A function with the following type: (unsanitized: string) => string
.
sanitize
is called with the raw string pulled from the URL search param.
If sanitize
throws an error, onError
will be called and useSearchParamState
will return the initial state.
sanitize
can be passed directly to useSearchParamState
, or to SearchParamStateProvider
. When a sanitize
option is passed to both, only the sanitize
passed to useSearchParamState
will be called.
sanitize
has no default value.
parse
A function with the following type: (unparsed: string) => TVal
.
The result of sanitize
is passed as the unparsed
argument to parse
.
If parse
throws an error, onError
will be called and useSearchParamState
will return the initial state.
parse
can be passed directly to useSearchParamState
, or to SearchParamStateProvider
. When a parse
option is passed to both, only the parse
passed to useSearchParamState
will be called.
parse
defaults to:
1export function defaultParse(unparsed: string) { 2 // JSON.parse errors on "undefined" 3 if (unparsed === "undefined") return undefined; 4 5 // Number parses "" to 0 6 if (unparsed === "") return ""; 7 8 // Number coerces bigints to numbers 9 const maybeNum = Number(unparsed); 10 if (!Number.isNaN(maybeNum)) return maybeNum; 11 12 try { 13 return JSON.parse(unparsed); 14 } catch { 15 return unparsed; 16 } 17}
validate
A function with the following type: (unvalidated: unknown) => TVal
.
The result of parse
is passed as the unvalidated
argument to validate
.
validate
is expected to validate and return the unvalidated
argument passed to it (presumably of type TVal
), or throw an error. If validate
throws an error, onError
will be called and useSearchParamState
will return the initial state.
validate
has no default value.
deleteEmptySearchParam
A boolean
.
When calling the setState
function returned by useSearchParamState
, if deleteEmptySearchParam
is true
and isEmptySearchParam
returns true
, the search param will be deleted from the URL.
deleteEmptySearchParam
defaults to false
.
isEmptySearchParam
A function with the following type: (searchParamVal: TVal) => boolean;
.
When calling the setState
function returned by useSearchParamState
, if deleteEmptySearchParam
is true
and isEmptySearchParam
returns true
, the search param will be deleted from the URL.
isEmptySearchParam
defaults to:
1function defaultIsEmptySearchParam<TVal>(searchParamVal: TVal) { 2 return ( 3 searchParamVal === null || 4 searchParamVal === undefined || 5 searchParamVal === "" 6 ); 7}
stringify
A function with the following type: (valToStringify: TVal) => string
.
stringify
is used to dehydrate the search param state before setting the stringified value in the URL.
If stringify
throws an error, onError
will be called and the URL will not be set.
stringify
can be passed directly to useSearchParamState
, or to SearchParamStateProvider
. When a stringify
option is passed to both, only the stringify
passed to useSearchParamState
will be called.
stringify
defaults to:
1function defaultStringify<TVal>(valToStringify: TVal) { 2 // avoid wrapping strings in quotes 3 if (typeof valToStringify === "string") return valToStringify; 4 return JSON.stringify(valToStringify); 5}
serverSideURL
A value of type string
- any valid string
input to the URL
constructor.
When passed, serverSideURL
will be used when window
is undefined
to access the URL search param. This is useful for generating content on the server, i.e. with Next.js:
1import url from "url"; 2 3export const getServerSideProps: GetServerSideProps = ({ req }) => { 4 const protocol = req.headers["x-forwarded-proto"] || "http"; 5 const serverSideURL = `${protocol}://${req.headers.host}${req.url}`; 6 7 return { 8 props: { serverSideURL }, 9 }; 10}; 11 12export default function Home({ 13 serverSideURL, 14}: InferGetServerSidePropsType<typeof getServerSideProps>) { 15 const [counter] = useSearchParamState("counter", 0, { 16 serverSideURL, 17 }); 18 19 // has the correct value for `counter` when rendered on the server 20 return <div>counter: {counter}</div>; 21}
Note that if no serverSideURL
option is passed and window
is undefined
, you may encounter hydration errors.
rollbackOnError
A boolean
.
When calling the setState
function returned by useSearchParamState
, pushState
will be called to set the URL search param with the latest React state value. If setting the search param in the URL throws an error, and rollbackOnError
is set to true
, the local React state will "rollback" to its previous value.
rollbackOnError
can be passed directly to useSearchParamState
, or to SearchParamStateProvider
. When a rollbackOnError
option is passed to both, only the rollbackOnError
passed to useSearchParamState
will be called.
rollbackOnError
defaults to false
.
pushState
A function with the following type: (href: string) => void
.
pushState
is called to set the search param state in the URL.
pushState
can be passed directly to useSearchParamState
, or to SearchParamStateProvider
. When a pushState
option is passed to both, only the pushState
passed to useSearchParamState
will be called.
pushState
defaults to:
1function defaultPushState(stringifiedSearchParams: string) {
2 window.history.pushState({}, "", stringifiedSearchParams);
3}
onError
A function with the following type: (e: unknown) => void
.
Most actions in useSearchParamState
are wrapped in a try
catch
block - onError
is called whenever the catch
block is reached. This includes situations when sanitize
, parse
, or validate
throw an error.
onError
can be passed directly to useSearchParamState
, or to SearchParamStateProvider
. When an onError
option is passed to both, both the functions will be called.
The best approach to test uses of useSearchParamState
is by mocking the window.location
property directly in your tests:
1Object.defineProperty(window, "location", {
2 writable: true,
3 value: { search: "?counter=1" },
4});
If you mutate window.location
directly, i.e.
1window.location = { search: "?counter=1" };
You may receive an error that window.location
is read-only.
Also note that since this library utilizes context, you'll need to use a wrappedRender
like the following when testing components outside your root:
1import { render, RenderOptions } from "@testing-library/react"; 2 3function wrappedRender( 4 ui: React.ReactElement, 5 options?: Omit<RenderOptions, "wrapper">, 6) { 7 const wrapper = ({ children }: { children: React.ReactNode }) => ( 8 <SearchParamStateProvider>{children}</SearchParamStateProvider> 9 ); 10 11 return render(ui, { wrapper, ...options }); 12}
If useSearchParamState
is used without a parent SearchParamStateProvider
, it'll throw an error.
No vulnerabilities found.
No security vulnerabilities found.