Gathering detailed insights and metrics for use-search-param-state
Gathering detailed insights and metrics for use-search-param-state
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 (96.77%)
JavaScript (2.53%)
Shell (0.7%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
3 Stars
159 Commits
1 Watchers
2 Branches
1 Contributors
Updated on Apr 05, 2025
Latest Version
3.0.2
Package Id
use-search-param-state@3.0.2
Unpacked Size
46.79 kB
Size
8.80 kB
File Count
7
NPM Version
11.2.0
Node Version
20.19.0
Published on
Apr 05, 2025
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
24
A hook to synchronize React state with URL search params.
Docs for version 2.0.13 (the last version before version 3.0.0) can be viewed here
1import { useSearchParamState } from "use-search-param-state"; 2 3function Demo() { 4 const [counterState, setCounterState] = useSearchParamState("counter", 0); 5}
or
1import {
2 useSearchParamState as _useSearchParamState,
3 UseSearchParamStateOptions,
4} from "use-search-param-state";
5import { z } from "zod";
6
7export function useSearchParamState<TVal>(
8 searchParam: string,
9 initialState: TVal,
10 options: UseSearchParamStateOptions<TVal>,
11) {
12 return _useSearchParamState(searchParam, initialState, {
13 sanitize: yourSanitizer,
14 ...options,
15 });
16}
17
18function Demo() {
19 const schema = z.number();
20 const [counterState, setCounterState] = useSearchParamState("counter", 0, {
21 validate: z.number().parse,
22 });
23}
On the first render, useSearchParamState
will read from the counter
URL search param. The counter
search param is read using the return value of the useURLSearchParams
hook.
If the window
object is undefined
(i.e on the server), useSearchParamState
will use the serverSideURLSearchParams
option. If serverSideURLSearchParams
is also not provided, counterState
will be returned initial state (i.e. 0
).
If the counter
search param does not exist (i.e. URLSearchParams.get
returns null
), counterState
will be returned as the initial state, and the counter
search param will be set to the initial state using the stringify
option. If enableSetInitialSearchParam
is set to false
, the counter
search param will not be set.
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 returned as the initial state.
If none of sanitize
, parse
, and validate
throw an error, counterState
is returned as the sanitized, parsed, and validated value in the counter
search param.
When setting the counter
search param using setCounterState
, the new state is stringified with the stringify
option, and the URL is set using the pushURLSearchParams
option. If setCounterState
is called with the replace
option, the replaceURLSearchParams
option is used instead of the pushURLSearchParams
option.
If deleteEmptySearchParam
is true
and isEmptySearchParam
returns true
, the search param will be deleted from the URL.
If stringify
or pushURLSearchParams
/replaceURLSearchParams
throw an error, onError
will be called and the URL will not be set.
1import { 2 useSearchParamState, 3 getSearchParam, 4 setSearchParam, 5 UseSearchParamStateOptions, 6 GetSearchParamOptions, 7 SetSearchParamOptions, 8} from "use-search-param-state"; 9import { useURLSearchParams } from "use-search-param-state/use-url-search-params";
useSearchParamState
vs getSearchParam
/setSearchParam
use-search-param-state
exports three main utilities: useSearchParamState
, getSearchParam
, and setSearchParam
.
The primary difference between useSearchParamState
and getSearchParam
/setSearchParam
is that useSearchParamState
is a hook, while getSearchParam
/setSearchParam
are functions. Because of this difference, useSearchParamState
is able to react to URL changes and always return the up-to-date search param value, while getSearchParam
provides a snapshot of the search param value at the time when it was called. Similarly, setSearchParam
will not force getSearchParam
to re-evaluate.
In React components, prefer to use useSearchParamState
. When the search param needs to be read or set outside React, getSearchParam
/setSearchParam
are hook-less alternatives with the same API.
1interface OptionReference { 2 /** 3 * `onError` defaults to the following function: 4 * 5 * ```ts 6 * export function defaultOnError(_e: unknown) { 7 * return; 8 * } 9 * ``` 10 * 11 * @param `error` The error caught in one of `try` `catch` blocks. 12 * @returns 13 */ 14 onError?: (error: unknown) => void; 15 16 /** 17 * `sanitize` defaults to the following function: 18 * 19 * ```ts 20 * const defaultSanitize = (unsanitized: string) => unsanitized; 21 * ``` 22 * 23 * If an error is thrown, `onError` is called and `useSearchParamState` returns the 24 * default state. If using `getSearchParam`, `null` is returned. 25 * 26 * @param `unsanitized` The raw string pulled from the URL search param. 27 * @returns The sanitized string. 28 */ 29 sanitize?: (unsanitized: string) => string; 30 31 /** 32 * 33 * `parse` defaults to the following function: 34 * 35 * ```ts 36 * export function defaultParse<TVal>(unparsed: string): TVal { 37 * // JSON.parse errors on "undefined" 38 * if (unparsed === "undefined") return undefined as TVal; 39 * 40 * try { 41 * return JSON.parse(unparsed) as TVal; 42 * } catch { 43 * return unparsed as TVal; 44 * } 45 * } 46 * ``` 47 * 48 * If an error is thrown, `onError` is called and `useSearchParamState` returns the 49 * default state. If using `getSearchParam`, `null` is returned. 50 * 51 * @param `unparsed` The result of `sanitize` is passed as `unparsed`. 52 * @returns A parsed value of the type `TVal` i.e. the type of `initialState`. 53 */ 54 parse?: (unparsed: string) => TVal; 55 56 /** 57 * `validate` is expected to validate and return the `unvalidated` argument passed to it 58 * (presumably of type `TVal`), or throw an error. 59 * 60 * `validate` defaults to the following function: 61 * 62 * ``` 63 * const defaultValidate = <TVal>(unvalidated: unknown) => unvalidated as TVal; 64 * ``` 65 * 66 * If an error is thrown, `onError` is called and `useSearchParamState` returns the 67 * default state. If using `getSearchParam`, `null` is returned. 68 * 69 * @param `unvalidated` The result of `parse` is passed as `unvalidated`. 70 * @returns The `unvalidated` argument, now validated as of type `TVal`. 71 */ 72 validate?: (unvalidated: unknown) => TVal; 73 74 /** 75 * When passed, `serverSideURLSearchParams` will be used when `window` is `undefined` to 76 * access the URL search param. This is useful for generating content on the server, 77 * i.e. with Next.js or Remix. 78 * 79 * `serverSideURLSearchParams` has no default. 80 * 81 * See MDN's documentation on the [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams) 82 * object for more info. 83 */ 84 serverSideURLSearchParams?: URLSearchParams; 85 86 /** 87 * When setting the search param, if `deleteEmptySearchParam` is set to `true` and 88 * `isEmptySearchParam` returns `true`, the search param will be deleted from the URL. 89 * 90 * `deleteEmptySearchParam` defaults to `false`. 91 */ 92 deleteEmptySearchParam?: boolean; 93 94 /** 95 * When setting the search param, if `deleteEmptySearchParam` is `true` and 96 * `isEmptySearchParam` returns `true`, the search param will be deleted from the URL. 97 * 98 * `isEmptySearchParam` defaults to the following function: 99 * 100 * ```ts 101 * export function defaultIsEmptySearchParam<TVal>(searchParamVal: TVal) { 102 * return ( 103 * searchParamVal === null || 104 * searchParamVal === undefined || 105 * searchParamVal === "" 106 * ); 107 * } 108 * ``` 109 * 110 * @param `searchParamVal` When setting the state, the new state is passed as 111 * `searchParamVal`. 112 * @returns A boolean. 113 */ 114 isEmptySearchParam?: (searchParamVal: TVal) => boolean; 115 116 /** 117 * `pushURLSearchParams` defaults to the following function: 118 * 119 * ```ts 120 * function defaultPushURLSearchParams(urlSearchParams: URLSearchParams) { 121 * const maybeQuestionMark = urlSearchParams.toString().length ? "?" : ""; 122 * window.history.pushState( 123 * {}, 124 * "", 125 * `${window.location.pathname}${maybeQuestionMark}${urlSearchParams.toString()}`, 126 * ); 127 *} 128 * ``` 129 * 130 * @param `urlSearchParams` The `urlSearchParams` to set 131 * returned by `useSearchParamState`. 132 * @returns 133 */ 134 pushURLSearchParams?: (urlSearchParams: URLSearchParams) => void; 135 136 /** 137 * `replaceURLSearchParams` defaults to the following function: 138 * 139 * ```ts 140 * function defaultReplaceURLSearchParams(urlSearchParams: URLSearchParams) { 141 * const maybeQuestionMark = urlSearchParams.toString().length ? "?" : ""; 142 * window.history.replaceState( 143 * {}, 144 * "", 145 * `${window.location.pathname}${maybeQuestionMark}${urlSearchParams.toString()}`, 146 * ); 147 * } 148 * ``` 149 * 150 * @param `urlSearchParams` The `urlSearchParams` to set 151 * returned by `useSearchParamState` with the `replace` option as `true`. 152 * @returns 153 */ 154 replaceURLSearchParams?: (urlSearchParams: URLSearchParams) => void; 155 156 /** 157 * `stringify` defaults to the following function: 158 * 159 * ```ts 160 * export function defaultStringify<TVal>(valToStringify: TVal) { 161 * // avoid wrapping strings in quotes 162 * if (typeof valToStringify === "string") return valToStringify; 163 * return JSON.stringify(valToStringify); 164 * } 165 * ``` 166 * 167 * @param `valToStringify` The search param to stringify before setting it in the URL. 168 * @returns The stringified search param. 169 */ 170 stringify?: (valToStringify: TVal) => string; 171 172 /** 173 * A React hook to return a URLSearchParams object representing the current search 174 * params. Note that this hook _must_ return a referentially stable value. 175 * 176 * `useURLSearchParams` defaults to an internal hook. 177 * 178 * See MDN's documentation on the [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams) 179 * object for more info. 180 */ 181 useURLSearchParams?: () => URLSearchParams; 182 183 /** 184 * If the search param state resolves to `null`, the URL is replaced with the search 185 * param set as the `initialState` option. 186 * 187 * `enableSetInitialSearchParam` defaults to `true` 188 */ 189 enableSetInitialSearchParam?: boolean; 190 191 /** 192 * A function to return the current URL object. 193 * 194 * `getURLSearchParams` defaults to the following function 195 * 196 * ```ts 197 * const defaultGetURLSearchParams = () => new URLSearchParams(window.location.search); 198 * ``` 199 * 200 * See MDN's documentation on the [URLSearchParams](https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams/URLSearchParams) 201 * object for more info. 202 */ 203 getURLSearchParams?: () => URLSearchParams; 204 205 /** 206 * If `true`, when setting the search param, the updated URL will replace the top item 207 * in the history stack instead of pushing to it. 208 * 209 * See MDN's documentation on [replaceState](https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState) 210 * for more info. 211 */ 212 replace?: boolean; 213}
useSearchParamState
options1interface UseSearchParamStateOptions<TVal> { 2 onError?: (error: unknown) => void; 3 4 // read options 5 serverSideURLSearchParams?: URLSearchParams; 6 sanitize?: (unsanitized: string) => string; 7 parse?: (unparsed: string) => TVal; 8 validate?: (unvalidated: unknown) => TVal; 9 10 // write options 11 stringify?: (valToStringify: TVal) => string; 12 deleteEmptySearchParam?: boolean; 13 isEmptySearchParam?: (searchParamVal: TVal) => boolean; 14 pushURLSearchParams?: (urlSearchParams: URLSearchParams) => void; 15 replaceURLSearchParams?: (urlSearchParams: URLSearchParams) => void; 16 17 // hook-only options 18 enableSetInitialSearchParam?: boolean; 19 useURLSearchParams?: () => URLSearchParams; 20}
getSearchParam
options1interface GetSearchParamOptions<TVal> { 2 onError?: (error: unknown) => void; 3 4 // read options 5 serverSideURLSearchParams?: URLSearchParams; 6 sanitize?: (unsanitized: string) => string; 7 parse?: (unparsed: string) => TVal; 8 validate?: (unvalidated: unknown) => TVal; 9 10 // function-only options 11 getURLSearchParams?: () => URLSearchParams; 12}
setSearchParam
options1interface SetSearchParamOptions<TVal> { 2 onError?: (error: unknown) => void; 3 4 // write options 5 stringify?: (valToStringify: TVal) => string; 6 deleteEmptySearchParam?: boolean; 7 isEmptySearchParam?: (searchParamVal: TVal) => boolean; 8 pushURLSearchParams?: (urlSearchParams: URLSearchParams) => void; 9 replaceURLSearchParams?: (urlSearchParams: URLSearchParams) => void; 10 11 // function-only options 12 getURLSearchParams?: () => URLSearchParams; 13 replace?: boolean; 14}
1/* 2 * - `parse`/`stringify` the `list` serach param as `?list=1_2_3` instead of `?list=%5B1%2C2%2C3%5D` 3 * - `validate` the parsed list as an array of numbers 4 * - delete the `list` search param when the current list has a length of 0 5 */ 6const [list, setList] = useSearchParamState<number[]>("list", [], { 7 deleteEmptySearchParam: true, 8 isEmptySearchParam: (currList) => { 9 return currList.length === 0; 10 }, 11 parse: (unparsed) => { 12 return unparsed.split("_").map((val) => Number(val)); 13 }, 14 validate: z.array(z.number()).parse, 15 stringify: (currList) => { 16 return currList.join("_"); 17 }, 18});
1import React from "react"; 2import { 3 useSearchParamState as _useSearchParamState, 4 UseSearchParamStateOptions, 5} from "use-search-param-state"; 6import { useRouter } from "next/router"; 7import { NextPageContext, InferGetServerSidePropsType } from "next"; 8import { stringify } from "querystring"; 9 10export function useSearchParamState<TVal>( 11 searchParam: string, 12 initialState: TVal, 13 options: UseSearchParamStateOptions<TVal> = {}, 14) { 15 const router = useRouter(); 16 17 function pushURLSearchParams(urlSearchParams: URLSearchParams) { 18 const maybeQuestionmark = urlSearchParams.toString().length ? "?" : ""; 19 router.push( 20 `${router.pathname}${maybeQuestionmark}${urlSearchParams.toString()}`, 21 undefined, 22 { shallow: true }, 23 ); 24 } 25 26 function replaceURLSearchParams(urlSearchParams: URLSearchParams) { 27 const maybeQuestionmark = urlSearchParams.toString().length ? "?" : ""; 28 router.replace( 29 `${router.pathname}${maybeQuestionmark}${urlSearchParams.toString()}`, 30 undefined, 31 { shallow: true }, 32 ); 33 } 34 35 return _useSearchParamState(searchParam, initialState, { 36 pushURLSearchParams, 37 replaceURLSearchParams, 38 ...options, 39 }); 40} 41 42function Page({ 43 serverSideSearchString, 44}: InferGetServerSidePropsType<typeof getServerSideProps>) { 45 const [count, setCount] = useSearchParamState("count", 0, { 46 serverSideURLSearchParams: new URLSearchParams(serverSideSearchString), 47 }); 48} 49 50export function getServerSideProps(ctx: NextPageContext) { 51 const dummyURL = new URL(ctx.req?.url ?? "", "http://a.com"); 52 const serverSideSearchString = dummyURL.search; 53 54 return { 55 props: { 56 serverSideSearchString, 57 }, 58 }; 59}
No vulnerabilities found.
No security vulnerabilities found.