Debouncing API Calls in React

Loading

Debouncing is a technique used to limit the number of API calls triggered by rapid user inputs (such as typing in a search field). It helps optimize performance by delaying the API call until the user has stopped typing for a specified period. This is particularly useful in scenarios like searching, filtering, or auto-completing where the user might trigger multiple requests in quick succession.

In this example, we’ll explore how to implement debouncing in React using useState, useEffect, and the setTimeout function, or by utilizing external libraries like Lodash.


1. Debouncing with setTimeout and useEffect

Basic Example:

Here’s how you can implement a simple debouncing technique for making API calls in React:

import React, { useState, useEffect } from 'react';

const DebounceSearch = () => {
  const [query, setQuery] = useState('');
  const [debouncedQuery, setDebouncedQuery] = useState('');
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  // Function to fetch data from an API
  const fetchData = async (query) => {
    if (!query) return; // Don't fetch if query is empty
    setLoading(true);
    try {
      const response = await fetch(`https://api.example.com/search?q=${query}`);
      const result = await response.json();
      setData(result);
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      setLoading(false);
    }
  };

  // Debounce the input change
  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedQuery(query); // Update the debounced query after delay
    }, 500); // Delay of 500ms

    // Clean up the timeout on component unmount or query change
    return () => clearTimeout(timer);
  }, [query]);

  // Fetch data when debounced query changes
  useEffect(() => {
    fetchData(debouncedQuery);
  }, [debouncedQuery]);

  return (
    <div>
      <input
        type="text"
        placeholder="Search..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      {loading && <p>Loading...</p>}
      <ul>
        {data.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default DebounceSearch;

Explanation:

  • query: This is the input value entered by the user.
  • debouncedQuery: This value updates after a delay, which is used to trigger the API call. It is updated only after the user stops typing for a specified amount of time (500ms in this case).
  • useEffect:
    • The first useEffect updates debouncedQuery after a delay using setTimeout.
    • The second useEffect triggers the fetchData function whenever debouncedQuery changes.
    • The setTimeout is cleared every time the user types, preventing an API call from being made until the user stops typing.

2. Debouncing with Lodash

Lodash is a utility library that provides a built-in debounce function, which simplifies the debouncing logic.

Install Lodash:

npm install lodash

Example with Lodash’s debounce:

import React, { useState, useEffect } from 'react';
import { debounce } from 'lodash';

const DebounceSearchWithLodash = () => {
  const [query, setQuery] = useState('');
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);

  // Function to fetch data from an API
  const fetchData = async (query) => {
    if (!query) return;
    setLoading(true);
    try {
      const response = await fetch(`https://api.example.com/search?q=${query}`);
      const result = await response.json();
      setData(result);
    } catch (error) {
      console.error('Error fetching data:', error);
    } finally {
      setLoading(false);
    }
  };

  // Debounced version of fetchData using Lodash's debounce
  const debouncedFetchData = debounce(fetchData, 500); // 500ms debounce delay

  useEffect(() => {
    debouncedFetchData(query); // Call debounced fetch
    return () => {
      debouncedFetchData.cancel(); // Cancel any pending debounced calls when component unmounts or query changes
    };
  }, [query]);

  return (
    <div>
      <input
        type="text"
        placeholder="Search..."
        value={query}
        onChange={(e) => setQuery(e.target.value)}
      />
      {loading && <p>Loading...</p>}
      <ul>
        {data.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
};

export default DebounceSearchWithLodash;

Explanation:

  • debounce: Lodash’s debounce function wraps the fetchData function, making sure that it is only called after the user stops typing for 500ms.
  • debouncedFetchData: This function is debounced, so each time the user types, the fetchData function is delayed.
  • cancel: The cancel method ensures that any pending debounced calls are canceled when the component unmounts or the query changes, preventing unnecessary API calls.

3. Benefits of Debouncing

  • Improved Performance: Instead of firing an API call on every keystroke, debouncing ensures that only the last keystroke within a certain timeframe triggers the API call.
  • Reduced Server Load: By limiting the number of API requests, debouncing reduces unnecessary server load.
  • Better User Experience: Users will notice faster interactions and less lag due to fewer API calls.

Leave a Reply

Your email address will not be published. Required fields are marked *