In this upcoming blog, our focus will be on understanding the process of returning values from a debounced rate-limiting function. Building on our previous discussion about rate limiting and its implementation over the traditional approach, we will explore how to effectively retrieve results from debounced functions. Stay tuned as we delve into this important aspect of web development!
Let's again revisit our Debouncing implementation
Upon careful examination of the Debouncing function, it becomes evident that the provided func, which is passed as an argument, will only be invoked when the setTimeout triggers.
What if we wish to extract information from the function we provide? In simpler terms, how can we obtain the return value of the passed function?
We can achieve this using Promise
So, to capture the return value from the function we provide, we can encapsulate the setTimeout within a Promise construct. This empowers us with two functions: resolve and reject, which can respectively convey the desired result or any encountered errors.
When the setTimeout completes, the function passed as an argument is fed into the resolve function. Consequently, the return value of this function is returned through the Promise.
If any errors arise during the execution of the provided function, we utilize the reject function to communicate the error.
This Promise instance is stored in a variable, and the enclosing function returns a reference to it. This process enables effective handling and retrieval of values from the function.
Let's modify our Debouncing function using the above approach
Our enhanced Debouncing function is now equipped to return values via the Promise reference.
Now, let's adjust the SearchBox component to align with the upgraded Debouncing function.
If we closely examine the searchFunctionality, we'll notice that instead of updating the state, we're now returning the filtered array.
Initialising the debouncFunc,
We initialize the debounceFunc function by passing the searchFunctionality function as the first argument and followed by the limit
below is the code.
In the recently revised SearchBox component, you'll notice that both debouncFunc and searchFunctionality are initialized outside of the component. This departure from the previous approach has a specific rationale.
The reason for this change lies in the way searchFunctionality is designed. In this implementation, there's no requirement for the setState function reference to update the filtered state, as was the case in the earlier example. Instead, the searchFunctionality directly returns the array itself. This self-contained behavior makes it independent of the state setter function.
Because searchFunctionality operates autonomously and doesn't rely on the state setter, it has been moved out of the component's state context. Consequently, the same applies to the debouncFunc function. This repositioning streamlines the structure and isolates the functionalities more efficiently.
But .. .but .. still . . . there are some difference left unaddressed .
if you remember the use of the useCallback hook in our earlier example. This hook serves a specific purpose: to prevent the creation of a new debounce function reference with every state update.
In our context, debouncFunc is a JavaScript variable. When the state updates, the function is re-initialized with the new timer reference. This behavior hampers the intended functionality of the debounce mechanism. The root cause of this issue lies in the fact that, due to JavaScript's nature, the debouncFunc variable gets re-initialized each time the state changes.
To counteract this, we employed the useCallback hook. By passing an empty array as a dependency, we ensured that the function is initialized only once and retains its reference throughout the component's lifecycle. This allowed us to maintain the desired behavior of the debounce function, effectively tackling the problem of the changing timer reference upon state updates.
Ha! finally all set ..... wait ......!
Now how will we update the state?
Now our function provides the reference of the Promise that is generated and returned by the Debouncing function. As a result, we can retrieve the val within the then state and subsequently update the state within the useEffect.
The updated useEffect.
In the end, our debouncFunc function has been successfully equipped to return values upon successful execution.
the updated code snippet is attached below
here is the link for codesandbox
Conclusion
The benefit of adopting this approach lies in the separation of state logic from the callback function (searchFunctionality). This separation enables us to manage state-related operations within the event handling mechanism, leading to a more organized and streamlined implementation.