useQueryState
Hookparamsync > hooks

useQueryState

Core reactive hook synchronizing individual URL search parameters with optimistic React state.

TSTypeScript Signature
IntelliSense
useQueryState<T>(key: string, parser: Parser<T>, options?: UseQueryStateOptions<T>): [T, (val: T | ((prev: T) => T)) => void, () => void, boolean]

What it does

Provides a [value, setValue, reset, isPending] tuple similar to useState. Automatically parses URL search params on mount and populates state. Setting state updates local React state immediately for 0ms typing feedback, and debounces or throttles Next.js router transitions in the background.

Best For

  • Search input boxes with debounce
  • Pagination page indices (?page=2)
  • Sorting drop-downs (?sort=price.asc)
  • Tab navigation and facet checkboxes

Configuration Options

OptionTypeDefaultDescription
defaultValueTundefinedFallback value returned when the query parameter is absent from the URL or invalid.
debounceMsnumber0Delay in milliseconds before synchronizing to the browser URL. Controlled inputs retain 0ms local responsiveness.
history'replace' | 'push''replace'Navigation mode. 'replace' avoids polluting browser history; 'push' creates a new back/forward history entry.
scrollbooleanfalseWhether Next.js should scroll to the top of the viewport after updating the URL.

Return Values

Return ValueTypeDescription
valueTThe current typed state value parsed from the URL query string.
setValue(valueOrUpdater: T | ((prev: T) => T)) => voidFunction to update state. Supports direct values or functional state updaters.
reset() => voidConvenience helper to reset state back to its defaultValue and purge the param from the URL.
isPendingbooleanReact useTransition flag indicating whether Next.js App Router background navigation is currently ongoing.

Usage Example

TSuseQueryStateExample.tsx
'use client';
 
import { useQueryState, parseAsString } from 'paramsync';
 
export function SearchBox() {
const [query, setQuery, reset, isPending] = useQueryState(
'q',
parseAsString.withDefault(''),
{
debounceMs: 300,
history: 'replace',
scroll: false,
}
);
 
return (
<div className="relative">
<input
type="text"
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search documentation..."
/>
{query && <button onClick={reset}>Clear</button>}
{isPending && <span>Updating URL...</span>}
</div>
);
}
main|paramsync
TypeScript JSXLn 28, Col 1

Advanced Techniques

TSexample.tsx
// Functional updates:
setQuery((prev) => prev.trim().toLowerCase());
 
// Resetting programmatically:
reset();
main|paramsync
TypeScript JSXLn 5, Col 1
;