Mastering Debouncing: Beyond API Calls - A Journey Through Efficient Event Handling
Ever wondered how your favorite websites make searches so smooth?
Debouncing: Simple Language
Let's keep things simple.
Example 1: Think of a 'cool down period' like after you type a letter, the computer takes a moment before it acts on it or do something right ? If you keep on typing and typing, it does waits until you pause and then do the thing. You got it! That what debouncing is actually. It's only after you stop typing that it does something.
Example 2: Imagine you're talking to someone and you only keep on saying. What the opposite one expects is to give a pause and let the other person act/react on what you said, then say again. That is what debouncing is and the pause that you gave may be one or two second for the other person to react, you can change timing of the network calls here also according to your wish.
Debouncing: Technical Language
Debouncing is a technique used to control how often a particular function gets called, especially in scenarios like search bars where there can be frequent input changes.
It ensures that a function is only called after a certain period of time has passed since the last time it was called.
This helps in optimizing performance by preventing unnecessary function calls, particularly in situations where frequent updates are not needed or may overload the system.
Let's see in action: API calls during Search
import { useEffect, useState } from "react"
export default function App() {
const [filter, setFilter] = useState("")
const [data, setData] = useState([])
// Function to debounce calls
let timeout;
const debounceGetData = () =>{
clearTimeout(timeout);
timeout = setTimeout(() => {
getData();
}, 1000); // Calls the getData function after 1000 milliseconds (1 second)
}
// Function to Fetch Data
const getData = async () => {
try {
const response = await fetch("https://api.agify.io?name=" + filter);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setData(data.age);
} catch (error) {
console.error('Error:', error);
// Optional: You can handle the error your way
}
}
// Use effect for triggering the dependency
useEffect(()=>{
debounceGetData(); // Calls the debounce function
// Cleanup function for the next call
return () => {
clearTimeout(timeout);
}
},[filter])
return (
<main>
<input onChange={e=>setFilter(e.target.value)} type="text"/>
<div>Data: {data}</div>
</main>
)
}
Output
Okay, now let's break down the code and understand it deeply!
State Variables
const [filter, setFilter] = useState("")
const [data, setData] = useState([])
filter
stores the user's input in the search bar every time the input changesdata
stores the fetched data from the API
Debouncing Function : with 1000ms timer
let timeout;
const debounceGetData = () =>{
clearTimeout(timeout);
timeout = setTimeout(() => {
getData();
}, 1000);
}
debounceGetData()
is a function that ensuresgetData()
is not called too frequently.It clears any existing timeouts and sets a new timeout of 1 second before calling
getData()
.This delays the API call until the user stops typing for at least 1 second or 1000 milisecond.
Fetching Data: Function for API call
const getData = async () => {
try {
const response = await fetch("https://api.agify.io?name=" + filter);
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
setData(data.age);
} catch (error) {
console.error('Error:', error);
}
}
getData()
function fetches data from an external API (https://api.agify.io
) based on the user's input stored infilter
.If the response is successful, it sets the fetched age data to the
data
state.Error handling is included to log any errors that occur during the fetch operation.
Purpose of useEffect Hook:
useEffect(()=>{
//FUNCTION -> debounceGetData()
debounceGetData();
// CLEANUP FUNCTION -> return()=>{}
return () => {
clearTimeout(timeout);
}
//dependency ->[filter]
},[filter])
It triggers
debounceGetData()
wheneverfilter
state changes (i.e., when the user types in the search bar).The cleanup function clears the timeout whenever
filter
state changes, ensuring only one API call is made after the user stops typing.
Input Element: OnChange method
<input onChange={e=>setFilter(e.target.value)} type="text"/>
Renders an input element (search bar) where users can type their search queries.
onChange
event handler updates thefilter
state when the user's input changes.
Displaying Data: Output
<div>Data: {data}</div>
- Displays the fetched data (
data.age
) below the search bar.
A General Case: Efficient API Calls
When a user types 'A' into the search box and then pauses for 1 second, here's what happens:
Initially, the
filter
state variable is empty.When the user types 'A', the
filter
state variable updates with the value 'A'.Since the
filter
dependency changes, theuseEffect
hook is triggered.The
useEffect
hook calls thedebounceGetData()
function, which sets a timer for 1 second before making the API call.If the user continues typing within that 1-second window, the
useEffect
hook will be triggered again due to the change in thefilter
dependency.However, before setting up a new timer, the cleanup function in the
useEffect
hook runs (in the second call). This clears the previous timer to prevent multiple API calls.Then, the
debounceGetData()
function is called again, setting up a new timer for 1 second.
If the cleanup function wasn't there, the debounceGetData()
function would start a new timer each time useEffect
is triggered, resulting in multiple timers running simultaneously. This would lead to multiple API calls being made, which is not the desired behavior. Therefore, the cleanup function ensures that only one timer is active at a time, preventing unnecessary API calls and ensuring that the API call only occurs after a 1-second pause in user input.
Other Use Cases:
Debouncing is a versatile concept that extends beyond just API calls. While we've just explored its application in managing API calls and async requests in a React application, its application is used in various scenarios in programming. Let's delve deeper into how debouncing can be employed in different contexts, using everyday examples to illustrate its significance.
1. Button Clicks and Form Submissions:
Okay, so imagine you're using a website, like when you're filling out a form or clicking on buttons. Sometimes, when you click a button or submit a form, it can trigger things to happen in the background, like sending information to the website's server or doing some heavy work.
Now, here's the thing: sometimes, if you click too quickly or accidentally press the button multiple times, it might cause problems. It could send the same information more than once, which can mess things up or slow things down.
So, to avoid this mess, developers use something called "debouncing." It's like putting a little delay or pause between each click or form submission. This way, even if you click the button a bunch of times in a row, it only registers once. It's like telling the website, "Hey, chill out a bit, I only meant to click once!" This helps prevent mistakes and keeps things running smoothly.
2. Autocomplete and Suggestions:
Now, imagine you're typing something in a search bar, like on Google or when you're writing an email. You know how it sometimes gives you suggestions as you type? That's called autocomplete.
Now, normally, every time you type a letter, the website or app might ask the server, "Hey, do you have any suggestions for what the user might be typing?" But if it did that for every single letter you type, it would put a lot of strain on the server, especially if you're typing fast.
So, to make things smoother and less stressful for the server, they use something called debouncing. It's like giving a little break between each letter you type. Instead of asking for suggestions after every single keystroke, the system waits for a moment when you stop typing for a bit. Then, it asks for suggestions. This way, it reduces the number of times it bothers the server and makes sure you still get those helpful suggestions without slowing things down. This makes your typing experience smoother and saves energy for the server.
Conclusion:
So, now that you understand debouncing and feel confident with it, I hope you found this helpful! If you did, please share it on social media and follow me here.
It won't cost you anything but it will encourage me to write more about similar topics in the future.
I build amazing cool stuffs. Check out my GitHub
Subscribe to my newsletter
Read articles from Aniket Sinha directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Aniket Sinha
Aniket Sinha
I'm dedicated to building products that people love ๐๐ปโจ And sometimes I write too!