Skip to main content

useDebounceValue

Overview

useDebounceValue delays updating a value until a specified time has elapsed since the last change. This is essential for performance-sensitive scenarios such as search inputs, filter controls, and API query parameters where you want to avoid firing requests on every keystroke. The hook returns the debounced value, which only updates after the caller stops changing the input for the given delay period.

Import

import { useDebounceValue } from "@/hooks/use-debounced-value";

API Reference

Parameters

ParameterTypeRequiredDefaultDescription
valueT (generic)Yes--The value to debounce. Can be any type (string, number, object, etc.).
delaynumberNo300Debounce delay in milliseconds. The debounced value updates only after this period of inactivity.

Generic Type Parameter

ParameterDescription
TThe type of the value being debounced. Inferred automatically from the value argument.

Return Value

PropertyTypeDescription
(return)TThe debounced value. Initially equals the input value and updates only after the delay has passed without further changes.

Usage Examples

Basic Usage

import { useDebounceValue } from "@/hooks/use-debounced-value";
import { useState } from "react";

function SearchInput() {
const [query, setQuery] = useState("");
const debouncedQuery = useDebounceValue(query, 400);

// debouncedQuery updates 400ms after the user stops typing
useEffect(() => {
if (debouncedQuery) {
fetchSearchResults(debouncedQuery);
}
}, [debouncedQuery]);

return (
<input
value={query}
onChange={(e) => setQuery(e.target.value)}
placeholder="Search..."
/>
);
}

Advanced Usage

import { useDebounceValue } from "@/hooks/use-debounced-value";
import { useState, useMemo } from "react";

interface FilterState {
category: string;
minPrice: number;
maxPrice: number;
}

function FilterPanel({ onFiltersChange }: { onFiltersChange: (f: FilterState) => void }) {
const [filters, setFilters] = useState<FilterState>({
category: "all",
minPrice: 0,
maxPrice: 1000,
});

const debouncedFilters = useDebounceValue(filters, 500);

useEffect(() => {
onFiltersChange(debouncedFilters);
}, [debouncedFilters, onFiltersChange]);

return (
<div>
<select
value={filters.category}
onChange={(e) => setFilters(prev => ({ ...prev, category: e.target.value }))}
>
<option value="all">All</option>
<option value="tools">Tools</option>
</select>
<input
type="range"
min={0}
max={1000}
value={filters.maxPrice}
onChange={(e) => setFilters(prev => ({ ...prev, maxPrice: Number(e.target.value) }))}
/>
</div>
);
}

Integration Patterns

useDebounceValue is a low-level building block used by higher-level hooks like useDebouncedSearch. It works with any React state that changes frequently and needs rate-limiting before triggering side effects. The hook uses a setTimeout/clearTimeout pattern internally and properly cleans up timers when the component unmounts or when dependencies change.

Best Practices

  • Use 200--500ms for search inputs to balance responsiveness with API load reduction. A delay of 300ms (the default) works well for most search scenarios.
  • Use longer delays (500--1000ms) for expensive operations like complex filter recalculations or heavy API queries.
  • Debounce the value, not the handler -- this hook debounces the output state rather than the event handler, which is simpler to compose with useEffect.
  • Remember that the initial render uses the non-debounced value, so downstream consumers receive the initial value immediately.
  • Combine with loading indicators to signal to users that results are pending while the debounce timer is active.
  • useDebouncedSearch -- Higher-level search hook that uses debouncing internally.
  • useFilters -- Filter management hook that benefits from debounced inputs.
  • usePaginatedQuery -- Paginated data fetching that often consumes debounced filter values.