DEV Community

Tanvir Azad
Tanvir Azad

Posted on

Debouncing beyond API Calls

At its core, debouncing is a programming practice that ensures a time-consuming function doesn't get called too frequently. It works by delaying the function execution until after a certain time has passed since it was last invoked.

Think of it like an elevator: instead of immediately moving after someone presses a button, it waits a few seconds to see if anyone else wants to get on before making the trip.

Before exploring use cases, let's implement a simple yet powerful useDebounce hook that you can use throughout your React applications:

import { useState, useEffect } from 'react';

function useDebounce(value, delay) {
  // State to store the debounced value
  const [debouncedValue, setDebouncedValue] = useState(value);

  useEffect(() => {
    // Set up a timer to update the debounced value after the specified delay
    const timer = setTimeout(() => {
      setDebouncedValue(value);
    }, delay);

    // Clean up the timer if value changes or component unmounts
    return () => {
      clearTimeout(timer);
    };
  }, [value, delay]);

  return debouncedValue;
}

export default useDebounce;
Enter fullscreen mode Exit fullscreen mode

This hook takes two parameters: the value you want to debounce and the delay in milliseconds. It returns the debounced value that updates only after the specified delay has passed without any new changes.


Practical Use Cases for Debouncing in React

1. Search Input Optimization

The classic example - and for good reason. Debouncing search inputs prevents unnecessary API calls as users type:

import React, { useState } from 'react';
import useDebounce from './hooks/useDebounce';

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

  // This effect will only run when debouncedSearchTerm changes
  useEffect(() => {
    if (debouncedSearchTerm) {
      fetchSearchResults(debouncedSearchTerm);
    }
  }, [debouncedSearchTerm]);

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

2. Form Input Validation

Improve user experience by validating form inputs only after users have paused typing:

function EmailInput() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');
  const debouncedEmail = useDebounce(email, 600);

  useEffect(() => {
    if (debouncedEmail) {
      validateEmail(debouncedEmail)
        ? setError('')
        : setError('Please enter a valid email address');
    }
  }, [debouncedEmail]);

  return (
    <div>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email address"
      />
      {error && <p className="error">{error}</p>}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

3. Auto-Save Functionality

Create a seamless auto-save experience for text editors or form inputs:

function AutosaveTextarea() {
  const [content, setContent] = useState('');
  const debouncedContent = useDebounce(content, 1000);

  useEffect(() => {
    // Only save when user has stopped typing for 1 second
    if (debouncedContent) {
      saveToLocalStorage(debouncedContent);
      // Or save to backend
      // saveToBackend(debouncedContent);
    }
  }, [debouncedContent]);

  return (
    <div>
      <textarea
        value={content}
        onChange={(e) => setContent(e.target.value)}
        placeholder="Start typing..."
      />
      <div className="status">
        {content !== debouncedContent ? 'Saving...' : 'Saved!'}
      </div>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Debounce vs. Throttle: Know the Difference

While debouncing delays function execution until after a certain time has passed, throttling ensures a function executes at a regular interval.

  • Debounce: Wait until user stops interacting before executing (good for "final value" scenarios)
  • Throttle: Execute periodically during interaction (good for "continuous update" scenarios)

Choose the appropriate technique based on your specific use case.


Next time you're dealing with frequent state updates or potentially expensive operations, consider whether a debounce might be the elegant solution you need. Happy Coding!

Top comments (0)