# useDebounceValue > State whose debounced copy updates after a pause. - Category: Effects - Package: `hookli` (install with `npm i hookli`) - Docs: https://hookli.vercel.app/docs/use-debounce-value ## Signature ```ts useDebounceValue(initialValue: T | (() => T), delayMs?: number, options?: DebounceOptions & { equalityFn?: (left: T, right: T) => boolean }): [T, DebouncedState<[T | ((prev: T) => T)], void>] ``` ## Parameters - `initialValue`: `T | (() => T)` — The starting value, or a factory evaluated once on mount — the same lazy-initializer contract as useState. - `delayMs`: `number` (default: `500`) — Milliseconds of inactivity before the debounced value catches up to the latest set value. - `options`: `DebounceOptions & { equalityFn? }` (default: `{}`) — DebounceOptions plus an optional equalityFn (left, right) => boolean — when it reports the values equal, the debounced update is skipped. See the tables below. ## Returns - `[0] debouncedValue`: `T` — The value that trails the setter, updating only after delayMs of quiet. - `[1] setValue`: `DebouncedState<[T | ((prev: T) => T)], void>` — A debounced setter accepting a value or updater; it also carries cancel, flush and isPending (see DebouncedState). ## Types ### DebounceOptions Controls how the debounced invocation is scheduled. - `leading`: `boolean` (default: `false`) — Invoke on the leading edge — run once immediately on the first call of a burst. - `trailing`: `boolean` (default: `true`) — Invoke on the trailing edge — run after the burst settles. - `maxWait`: `number` — The maximum time the callback may be delayed before it is forced to run, even during a continuous burst. ### DebouncedState The debounced function, plus manual control methods. - `(...args)`: `(...args: Args) => R | undefined` — Calling it schedules an invocation and returns the last computed result — undefined before the first run. - `cancel`: `() => void` — Cancels any pending trailing invocation. - `flush`: `() => R | undefined` — Immediately runs any pending invocation and returns its result. - `isPending`: `() => boolean` — Whether a trailing invocation is currently scheduled. ## Usage ```tsx import { useState } from "react"; import { useDebounceValue } from "hookli"; export function Demo() { const [text, setText] = useState(""); const [debounced, setValue] = useDebounceValue("", 500); return (
{ setText(e.target.value); setValue(e.target.value); }} />

Debounced: {debounced}

); } ``` ## Source `src/hooks/use-debounce-value/use-debounce-value.ts` ```ts import { useEffect, useRef, useState } from "react"; import { useDebounceCallback, type DebounceOptions, type DebouncedState, } from "../use-debounce-callback/use-debounce-callback"; export type UseDebounceValueReturn = [ T, DebouncedState<[value: T | ((prev: T) => T)], void>, ]; export const useDebounceValue = ( initialValue: T | (() => T), delayMs = 500, options: DebounceOptions & { equalityFn?: (left: T, right: T) => boolean } = {}, ): UseDebounceValueReturn => { const eq = options.equalityFn ?? ((left, right) => left === right); const unwrap = (v: T | (() => T)): T => typeof v === "function" ? (v as () => T)() : v; const [debouncedValue, setDebouncedValue] = useState(() => unwrap(initialValue), ); const previousValue = useRef(debouncedValue); const updateDebouncedValue = useDebounceCallback( (value: T | ((prev: T) => T)) => { const next = typeof value === "function" ? (value as (prev: T) => T)(previousValue.current) : value; if (!eq(previousValue.current, next)) { previousValue.current = next; setDebouncedValue(next); } }, delayMs, options, ); useEffect(() => { return () => updateDebouncedValue.cancel(); }, [updateDebouncedValue]); return [debouncedValue, updateDebouncedValue]; }; ```