Understanding the debounce function and how it can be used to control API requests
Have you noticed when using any generic search bar across the web there is often a small delay before your search results appear. This functionality is often controlled by a debounce function, which prevents the search API request from being made until the user stops typing for a pre-determined set of time. Without it, a large number of redundant requests will be made, with one being made per keystroke event by the user.
Let's see it in action
As demonstrated above, it is clear that the debounced input results in 1 API call in total compared to 4 API calls for a non-debounced input. In addition to this, with our debounced input the API call is made exactly 1000ms delay after the final key input is made, while it is made instantly with the non-debounced input.
What’s wrong with non-debounced API calls?
In short nothing, but…it all depends on your circumstances. In my current role, we have an entire middleware/backend team that ensure our APIs are high performing and capable of taking very high load — so the risk of flooding them is low, yet we still use debouncing since it is good practice.
In other circumstances when there are set limits on the number of calls you can make to your backend, debouncing can be key. Just from the small example above, it can reduce redundant API calls by 300% — which is a huge saving.
The function itself
I like to take advantage of as many open-source libraries as possible in my work. What's the point in overcomplicating things when there already done for you?
Lodash’s library provides a debounce function out the box which can be easily imported into your react project.
This is the standard debounce function that returns a debounced version of a given function (in this case onChange), which will be called after 400ms has elapsed.
Using in React
Unfortunately, we can’t use the function above directly within our react app, since on every re-rendering of the DOM a new instance of myDebounceFunction will be made. Instead, we want to use the same instance of myDebounceFunction and thus must cache the initial instance of the function using React.useCallback.
We now have the same instance of the debounceOnChange function no matter how much re-rendering is done. It can be triggered sparingly throughout our app in order to make API requests.
On line 29 onChange calls debounceOnChange and passes the inputted value to it, which will be received by the onChange function on line 8, and API request will be made to https://mocki.io/. The state is then set to the API response and rendered as a list.
Above we can see our debounced API call is made 0.4s after the final onChange (keystroke) event is triggered — returning our world city data. This could instead be a list of search results with the delay reduced below 0.4s such that isn’t noticeable to the user.