← Back to all hooks

useDebounce

Delay execution until activity stops. Perfect for search inputs, form validation, and reducing API calls.

Live Demo

Try typing in the search box or clicking the button rapidly. Notice how the debounced value only updates after you stop.

🔍 Value Debouncing (Search)

Current Value: (empty)
Debounced Value: (empty)
💡 API call only fires after you stop typing for 500ms

🖱️ Function Debouncing (Button)

Execution Count
0
💡 Only executes after you stop clicking for 1 second

📝 Event Log

No events yet. Try typing or clicking!

💡 How It Works:

  • Delays execution until activity stops
  • Perfect for search inputs and form validation
  • Reduces API calls and improves performance
  • Only the last call executes after the delay

Code Examples

Search Input Debouncing

import { useDebounce } from "@uiblock/hooks";
import { useState, useEffect } from "react";

export default function SearchBox() {
  const [searchTerm, setSearchTerm] = useState('');
  const debouncedSearchTerm = useDebounce(searchTerm, 500);

  useEffect(() => {
    if (debouncedSearchTerm) {
      // API call only fires after user stops typing
      fetch(`/api/search?q=${debouncedSearchTerm}`)
        .then(res => res.json())
        .then(data => console.log(data));
    }
  }, [debouncedSearchTerm]);

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

Form Validation

import { useDebounce } from "@uiblock/hooks";
import { useState, useEffect } from "react";

export default function UsernameInput() {
  const [username, setUsername] = useState('');
  const [isAvailable, setIsAvailable] = useState<boolean | null>(null);
  const debouncedUsername = useDebounce(username, 300);

  useEffect(() => {
    if (debouncedUsername) {
      checkUsernameAvailability(debouncedUsername)
        .then(setIsAvailable);
    }
  }, [debouncedUsername]);

  return (
    <div>
      <input
        value={username}
        onChange={(e) => setUsername(e.target.value)}
      />
      {isAvailable !== null && (
        <span>{isAvailable ? '✅ Available' : '❌ Taken'}</span>
      )}
    </div>
  );
}

Debounced Callback

import { useDebouncedCallback } from "@uiblock/hooks";

export default function AutoSave() {
  const saveData = useDebouncedCallback(async (data) => {
    await fetch('/api/save', {
      method: 'POST',
      body: JSON.stringify(data)
    });
    console.log('Saved!');
  }, 1000);

  return (
    <textarea
      onChange={(e) => saveData({ content: e.target.value })}
      placeholder="Type to auto-save..."
    />
  );
}

How It Works

Here's the implementation:

import { useState, useEffect, useCallback, useRef } from 'react'

// Value debouncing
export function useDebounce<T>(value: T, delay: number): T {
  const [debouncedValue, setDebouncedValue] = useState<T>(value)

  useEffect(() => {
    const handler = setTimeout(() => {
      setDebouncedValue(value)
    }, delay)

    return () => {
      clearTimeout(handler)
    }
  }, [value, delay])

  return debouncedValue
}

// Function debouncing
export function useDebouncedCallback<T extends (...args: any[]) => any>(
  callback: T,
  delay: number
): T {
  const timeoutRef = useRef<NodeJS.Timeout | null>(null)

  return useCallback(
    ((...args: Parameters<T>) => {
      if (timeoutRef.current) {
        clearTimeout(timeoutRef.current)
      }
      
      timeoutRef.current = setTimeout(() => {
        callback(...args)
      }, delay)
    }) as T,
    [callback, delay]
  )
}

API Reference

useDebounce

value: T

The value to debounce

delay: number

Delay in milliseconds

Returns: T - The debounced value

useDebouncedCallback

callback: T

Function to debounce

delay: number

Delay in milliseconds

Returns: T - Debounced version of the callback

💡 Use Cases

  • Search autocomplete and suggestions
  • Form validation (username, email availability)
  • Auto-save functionality
  • Reducing API calls
  • Window resize handlers
  • Text input processing