JAVASCRIPT

Build a `useDebounce` Custom Hook

Create a custom React `useDebounce` hook to delay execution of a function until after a certain period of inactivity, optimizing performance for frequent events like typing.

import { useState, useEffect } from 'react';

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

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

    // Cleanup function to clear the timeout if value or delay changes
    // or if the component unmounts. This ensures only the last value is processed.
    return () => {
      clearTimeout(handler);
    };
  }, [value, delay]); // Re-run effect if value or delay changes

  return debouncedValue;
}

// Example usage component
function DebouncedSearchInput() {
  const [searchTerm, setSearchTerm] = useState('');
  const debouncedSearchTerm = useDebounce(searchTerm, 500); // 500ms debounce delay
  const [results, setResults] = useState([]);
  const [isSearching, setIsSearching] = useState(false);

  // Effect to fetch API data when debounced search term changes
  useEffect(() => {
    if (debouncedSearchTerm) {
      setIsSearching(true);
      // Simulate an API call
      const fetchResults = async () => {
        await new Promise(resolve => setTimeout(resolve, 800)); // Simulate network delay
        setResults([
          `Result for: ${debouncedSearchTerm} 1`,
          `Result for: ${debouncedSearchTerm} 2`,
          `Result for: ${debouncedSearchTerm} 3`
        ]);
        setIsSearching(false);
      };
      fetchResults();
    } else {
      setResults([]);
    }
  }, [debouncedSearchTerm]); // Only re-run when the debounced term changes

  return (
    <div>
      <h1>Debounced Search</h1>
      <p>Type to search. API call will be delayed until you stop typing for 500ms.</p>
      <input
        type="text"
        placeholder="Search..."
        value={searchTerm}
        onChange={(e) => setSearchTerm(e.target.value)}
        style={{ width: '300px', padding: '8px', fontSize: '16px' }}
      />
      {isSearching && <p>Searching...</p>}
      <ul>
        {results.map((result, index) => (
          <li key={index}>{result}</li>
        ))}
      </ul>
    </div>
  );
}

export default DebouncedSearchInput;
How it works: The `useDebounce` custom hook takes a `value` and a `delay` as arguments. It returns a new `debouncedValue` that only updates after the `value` has remained unchanged for the specified `delay`. Inside the `useEffect`, a `setTimeout` is set to update `debouncedValue`. Crucially, if the `value` changes again before the timeout completes, the previous timeout is cleared using `clearTimeout`, and a new one is set. This ensures that the `debouncedValue` (and subsequent side effects, like an API call) only triggers once the user has stopped inputting for the debounce duration, preventing excessive function calls and optimizing performance for interactive elements like search bars.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs