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
updatesdebouncedQuery
after a delay usingsetTimeout
. - The second
useEffect
triggers thefetchData
function wheneverdebouncedQuery
changes. - The
setTimeout
is 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’sdebounce
function wraps thefetchData
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, thefetchData
function is delayed.cancel
: Thecancel
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.