Hookparamsync > hooks
useQueryState
Core reactive hook synchronizing individual URL search parameters with optimistic React state.
TSTypeScript Signature
IntelliSenseuseQueryState<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
| Option | Type | Default | Description |
|---|---|---|---|
| defaultValue | T | undefined | Fallback value returned when the query parameter is absent from the URL or invalid. |
| debounceMs | number | 0 | Delay 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. |
| scroll | boolean | false | Whether Next.js should scroll to the top of the viewport after updating the URL. |
Return Values
| Return Value | Type | Description |
|---|---|---|
| value | T | The current typed state value parsed from the URL query string. |
| setValue | (valueOrUpdater: T | ((prev: T) => T)) => void | Function to update state. Supports direct values or functional state updaters. |
| reset | () => void | Convenience helper to reset state back to its defaultValue and purge the param from the URL. |
| isPending | boolean | React 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 JSX|UTF-8|Ln 28, Col 1
Advanced Techniques
TSexample.tsx
// Functional updates:setQuery((prev) => prev.trim().toLowerCase()); // Resetting programmatically:reset();main|paramsync
TypeScript JSX|UTF-8|Ln 5, Col 1