useDebounced
Delay a value until typing stops — the one debounce the framework's own bindings use.
Every app that has a search box eventually writes the same six lines: a
useState, a useEffect, a setTimeout, and a cleanup that clears it. Get the
cleanup wrong and stale timers fire after unmount; get the dependency array
wrong and the timer never restarts. useDebounced is that snippet, written
once. useAsyncValidation and useQueryField are built on it, so a debounced
subscription in your code behaves exactly like the framework's own.
import { useDebounced } from '@voltro/client'
const [term, setTerm] = useState('')
const debouncedTerm = useDebounced(term, 300)
const results = useSubscription('app', 'todos.search', { term: debouncedTerm })The whole API is useDebounced(value, ms = 300). There is no options object —
no leading edge, no maxWait, no flush() or cancel(). It is a trailing-edge
debounce and nothing else. If you need one of those, you need a different
primitive, not a flag on this one.
It is generic over the value, not limited to strings: useDebounced(filters)
over an object works the same way.
Two behaviours worth knowing before you use it
The first value is not delayed. The internal state is seeded with value on
the very first render, so the initial value is returned synchronously — including
during SSR, where no timer ever fires. Only changes wait for the quiet window.
That is what you want (no empty first paint), but it means you cannot use the
"debounced value hasn't caught up yet" trick to detect the initial render.
Comparing the two is how you detect pending input, which is exactly what
useAsyncValidation does internally to show its checking state:
const settling = term !== debouncedTermThe value is compared by identity. value and ms are the effect's
dependencies, so a value that is a fresh object or array on every render
restarts the timer on every render. Pass primitives, or memoize:
const filters = useMemo(() => ({ status, assignee }), [status, assignee])
const debouncedFilters = useDebounced(filters, 300)Changing ms restarts the quiet window too, for the same reason — so derive the
delay from something stable rather than recomputing it inline.