CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-use-debounce

React hooks library for debouncing and throttling functionality with small footprint and comprehensive control features

Pending
Overview
Eval results
Files

value-debouncing.mddocs/

Value Debouncing

Value debouncing with useDebounce delays value updates until a specified delay has passed without changes. This is perfect for optimizing React component re-renders when dealing with rapidly changing state values like user input, search queries, or form fields.

Capabilities

useDebounce Hook

Creates a debounced version of a value that only updates after the specified delay period.

/**
 * Debounces a value, delaying updates until after delay milliseconds have elapsed
 * since the last time the value changed.
 * 
 * @param value - The value to debounce
 * @param delay - The number of milliseconds to delay
 * @param options - Optional configuration object
 * @returns Tuple of [debouncedValue, controlFunctions]
 */
function useDebounce<T>(
  value: T,
  delay: number,
  options?: {
    maxWait?: number;
    leading?: boolean;
    trailing?: boolean;
    equalityFn?: (left: T, right: T) => boolean;
  }
): [T, DebouncedState<(value: T) => void>];

Parameters:

  • value: T - The value to debounce (can be any type)
  • delay: number - Delay in milliseconds before updating the debounced value
  • options - Optional configuration object with:
    • maxWait?: number - Maximum time the value is allowed to be delayed before it's updated
    • leading?: boolean - If true, updates the value immediately on first change, then debounces subsequent changes
    • trailing?: boolean - If true (default), updates the value after the delay period
    • equalityFn?: (left: T, right: T) => boolean - Custom equality function to determine if the value has changed (defaults to ===)

Returns:

  • [T, DebouncedState] - A tuple containing the debounced value and control functions (cancel, flush, isPending)

Usage Examples:

import React, { useState } from 'react';
import { useDebounce } from 'use-debounce';

// Basic text input debouncing
function SearchInput() {
  const [searchTerm, setSearchTerm] = useState('');
  const [debouncedSearchTerm] = useDebounce(searchTerm, 500);

  // This effect will only run when debouncedSearchTerm changes
  React.useEffect(() => {
    if (debouncedSearchTerm) {
      // Perform API search
      console.log('Searching for:', debouncedSearchTerm);
    }
  }, [debouncedSearchTerm]);

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

// Leading option - immediate first update
function InstantSearch() {
  const [query, setQuery] = useState('');
  const [debouncedQuery] = useDebounce(query, 1000, { leading: true });

  // First change updates immediately, subsequent changes are debounced
  return (
    <div>
      <input value={query} onChange={(e) => setQuery(e.target.value)} />
      <p>Debounced: {debouncedQuery}</p>
    </div>
  );
}

// With control functions
function ControlledDebounce() {
  const [text, setText] = useState('');
  const [debouncedText, { cancel, flush, isPending }] = useDebounce(text, 1000);

  return (
    <div>
      <input value={text} onChange={(e) => setText(e.target.value)} />
      <p>Text: {text}</p>
      <p>Debounced: {debouncedText}</p>
      <button onClick={cancel}>Cancel</button>
      <button onClick={flush}>Flush Now</button>
      <p>Pending: {isPending() ? 'Yes' : 'No'}</p>
    </div>
  );
}

// Custom equality function for objects
function ObjectDebounce() {
  const [user, setUser] = useState({ name: '', email: '' });
  const [debouncedUser] = useDebounce(
    user,
    500,
    {
      equalityFn: (prev, next) => 
        prev.name === next.name && prev.email === next.email
    }
  );

  return (
    <div>
      <input
        value={user.name}
        onChange={(e) => setUser({ ...user, name: e.target.value })}
        placeholder="Name"
      />
      <input
        value={user.email}
        onChange={(e) => setUser({ ...user, email: e.target.value })}
        placeholder="Email"
      />
      <p>Debounced: {JSON.stringify(debouncedUser)}</p>
    </div>
  );
}

// MaxWait option
function MaxWaitExample() {
  const [value, setValue] = useState('');
  const [debouncedValue] = useDebounce(value, 500, { maxWait: 2000 });

  // Will update after 500ms of no changes, or after 2000ms maximum
  return (
    <div>
      <input value={value} onChange={(e) => setValue(e.target.value)} />
      <p>Debounced (max 2s): {debouncedValue}</p>
    </div>
  );
}

Control Functions

The debounced state includes control functions for managing the debounce behavior:

interface ControlFunctions<ReturnT> {
  /** Cancel any pending debounced updates */
  cancel: () => void;
  /** Immediately execute any pending debounced updates */
  flush: () => ReturnT | undefined;
  /** Check if there are any pending debounced updates */
  isPending: () => boolean;
}

Control Methods:

  • cancel() - Cancels any pending debounced value updates
  • flush() - Immediately applies any pending debounced value updates
  • isPending() - Returns true if there's a pending debounced update, false otherwise

Common Patterns

Form Input Optimization

function OptimizedForm() {
  const [formData, setFormData] = useState({
    username: '',
    email: '',
    message: ''
  });
  
  // Debounce the entire form object
  const [debouncedFormData] = useDebounce(formData, 300);
  
  // Only validate when debounced data changes
  React.useEffect(() => {
    validateForm(debouncedFormData);
  }, [debouncedFormData]);
  
  return (
    <form>
      <input
        value={formData.username}
        onChange={(e) => setFormData(prev => ({
          ...prev,
          username: e.target.value
        }))}
      />
      {/* More form fields... */}
    </form>
  );
}

API Request Debouncing

function AutoSuggest() {
  const [query, setQuery] = useState('');
  const [suggestions, setSuggestions] = useState([]);
  const [debouncedQuery] = useDebounce(query, 400);
  
  React.useEffect(() => {
    if (debouncedQuery.length > 2) {
      fetch(`/api/suggestions?q=${debouncedQuery}`)
        .then(res => res.json())
        .then(setSuggestions);
    } else {
      setSuggestions([]);
    }
  }, [debouncedQuery]);
  
  return (
    <div>
      <input
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      <ul>
        {suggestions.map(suggestion => (
          <li key={suggestion.id}>{suggestion.text}</li>
        ))}
      </ul>
    </div>
  );
}

Install with Tessl CLI

npx tessl i tessl/npm-use-debounce

docs

callback-debouncing.md

index.md

throttling.md

value-debouncing.md

tile.json