Delay a Function Call using React Custom Hook: Debounce
Nicholas G
Posted on February 7, 2023
What is Debouncing?
Debouncing is a technique or pattern in programming that limits the number of times a function can be executed within a specific time interval.
Why is Debouncing Important?
Debouncing can prevent an application from becoming slow or unresponsive. It is used to improve the performance and responsiveness of applications.
In React, one place where we may use debouncing is with text input fields in order to prevent the execution of an expensive function, such as a data fetch, until the user has finished typing.
For example, let's say we are programming a notes app with a text input field. After the user finishes typing, we would like the app to automatically save the user input text and commit these changes to the server. Without debouncing, a server request would be made with each letter typed. In that case, a small paragraph could trigger a few hundred fetch requests! As you could imagine, this can quickly slow the app's performance and, because many API's limit the number of requests made in a given time period, this may reach the request limit and prevent the app from properly communicating with the server. Not good!
Using debouncing, the fetch request can be delayed until X number of seconds after the user has finished typing. Even delaying the function call by just 1 to 2 seconds can greatly improve the performance of the application and lower the number of requests made to and from the API server!
One common way to implement debouncing in our code is to create a custom hook to handle this functionality.
What is a Custom Hook?
Custom hooks are a feature in React that allow you to extract code and reuse it across multiple components. With custom hooks, you can create the logic for debouncing a function in a hook and make it reusable and easy to use across your application. This helps limit repeated code and keep your code "DRY".
Note: There are several ways to debounce a function in React. Creating a custom hook is just one way to do it, but this code can also be altered and written directly in the component where your function exists.
Creating a Custom Hook for Debounce
A common approach to debouncing is to use the setTimeout()
and clearTimeout()
methods. These methods set a timer which executes a function once the timer expires. Read the official documentation for these methods here.
To create a custom hook for debouncing, we will write a function that returns a debounced value using the setTimeout()
and clearTimeut()
methods. The hook will take two arguments: the value to be debounced, and the debouncing delay (a number in milliseconds).
Here is the code for our custom hook:
import { useState, useEffect } from "react";
const useDebounce = (value, delay) => {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const timeoutID = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => clearTimeout(timeoutID);
}, [value, delay]);
return debouncedValue;
};
export default useDebounce;
In the code above, the hook uses the useState
hook to store the debounced value in debouncedValue
. The useEffect
hook is used to update the debounced value whenever the original value or the debouncing delay changes by listing them as dependencies.
The debouncing logic itself is written inside the useEffect
hook. Using setTimeout()
, the variable debouncedValue
is set to state using the function setDebouncedValue()
. The method setTimeout()
returns a timer ID which is saved to the variable timeoutID
. This ID is later called by clearTimeout()
in order to clear the timeout function if it is called again within the set time interval.
Using the Hook
To use the hook, import it and call it into a component. The hook returns the debounced value, which you can then use in your component as needed.
Let's return to our earlier example of the notes app. Here is an extremely simplified example of how we could use this hook in our component:
import { useState, useEffect } from "react";
import useDebounce from "./useDebounce";
const App = () => {
const [value, setValue] = useState("");
const debouncedValue = useDebounce(value, 2000);
useEffect(() => {
//Write Your Function Here!!
console.log("EXAMPLE FETCH CALL:", debouncedValue);
}, [debouncedValue]);
const handleChange = (e) => {
setValue(e.target.value);
};
return <textarea onChange={handleChange} />;
};
export default App;
In the code above, the component uses the useDebounce
hook to debounce the setValue
function. The hook is called with value
as the first argument and 2000 as the second argument, meaning that the debounced function will be executed after 2000 milliseconds (2 seconds). Another useEffect
hook is used with the dependency set to debouncedValue
in order to execute when the debounced value is returned, thus triggering out fetch request.
And there you have it! In the case of our notes app example described above, the changes to the text input can be automatically committed to the server using this code.
Resources
Find out more about React hooks in general in the official React Documentation here.
Find out more about creating custom hooks here.
Conclusion
Debouncing is a useful technique for improving the performance and responsiveness of applications. In React, debouncing can be easily implemented using the setTimeout()
function. By debouncing a function, you can prevent it from being executed too frequently, which can improve the overall performance of your application.
Posted on February 7, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.