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
useEffectupdatesdebouncedQueryafter a delay usingsetTimeout. - The second
useEffecttriggers thefetchDatafunction wheneverdebouncedQuerychanges. - The
setTimeoutis cleared every time the user types, preventing an API call from being made until the user stops typing.
- The first
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’sdebouncefunction wraps thefetchDatafunction, 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, thefetchDatafunction is delayed.cancel: Thecancelmethod 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.
