Ever felt your app making too many API calls when typing or scrolling? Or your UI freezing during fast interactions? That’s where debouncing, throttling, and request batching come in — underrated techniques that can drastically reduce unnecessary renders and network overhead.
In this part of the React Performance series, we’ll break down:
- What these techniques are
- When and how to use them
- Real-world examples in React
- Tools and patterns that help
🚀 Main Content:
🔄 Debouncing: Delay the Action
- What is it? Waits until user stops triggering the action for a specified time.
- Use case: Search inputs, filters, live suggestions.
- React example using lodash:
import { debounce } from 'lodash';
import { useCallback } from 'react';
const Search = () => {
const handleSearch = useCallback(
debounce((query) => {
fetch(`/api/search?q=${query}`);
}, 500),
[]
);
return <input onChange={(e) => handleSearch(e.target.value)} />;
};
🧊 Throttling: Limit the Frequency
- What is it? Ensures a function executes only once every X milliseconds.
- Use case: Scroll, resize events.
- React example:
import { throttle } from 'lodash';
import { useEffect } from 'react';
const ScrollTracker = () => {
useEffect(() => {
const handleScroll = throttle(() => {
console.log('Scrolling...');
}, 300);
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return <div>Scroll to see throttle in action</div>;
};
📦 Request Batching: Merge Multiple Requests
- What is it? Combining multiple API requests into one to reduce network load.
- Use case: GraphQL (native support), REST batching, React Query batching.
Example with Apollo Client (GraphQL):
import { ApolloClient, InMemoryCache } from '@apollo/client';
import { BatchHttpLink } from '@apollo/client/link/batch-http';
const client = new ApolloClient({
cache: new InMemoryCache(),
link: new BatchHttpLink({
uri: '/graphql',
batchMax: 5,
batchInterval: 20,
}),
});
Bonus: React Query’s batchCalls
(manual grouping pattern)
const useBatchedData = () => {
return useQuery(['batchedData'], async () => {
const [a, b] = await Promise.all([
fetch('/api/a').then(res => res.json()),
fetch('/api/b').then(res => res.json())
]);
return { a, b };
});
};
💡 Key Takeaways:
- Debounce for waiting until user stops typing.
- Throttle for limiting frequent events like scroll/resize.
- Batch requests to reduce server load.
- Combine these with React Query, TanStack Router, or Apollo for smooth UX and blazing speed.
🧰 Tools & Libraries:
-
lodash
(debounce/throttle) -
use-debounce
(React hook) apollo-link-batch-http
tanstack/query
- Custom batching for REST APIs
🔚 Conclusion:
Small tweaks like debouncing and throttling can make a huge difference in perceived performance and server costs. When paired with smart request batching, your app becomes more scalable, responsive, and production-ready.
In Part 5, we’ll cover Code Splitting, Dynamic Imports & Bundle Analysis — the next layer of optimizing performance at the build level.
Top comments (0)