DEV Community

Mertcan KOÇER
Mertcan KOÇER

Posted on

Custom Hooks - useDebounce()

Hi everyone,

Today's hook is debouncing. But before I tell you about this hook, let me explain what debouncing is.

What is Debouncing?

As you know, we love to use fancy words in computer world. One of them is debouncing.

Imagine that you have a user table in database that contains a large amount of data, and you want to display these users in your react application and also be able to search on it.

But the search action takes too long. That's why you don't want to send every input of the user as a request. What solution can you provide? We have 3 solutions as below.

1. Sending data when it reaches a certain length

Certain Length Search

But what if the length of our smallest meaningful data is one character? Or, are we going to request every character input after the threshold value we set? Of course no!

2. Using button to send data

Submit Search

Yes, I think the same as you 🙂 Definitely, this is a solution but we can not provide the necessary feedback instantly. It's like we are using a technology from decades ago, not React. Let's do better things now!

3. Send data when the data entry is complete

Debounce Search

In fact, we understand what debounce means in this example. We offer the user the opportunity to enter the desired word. If the user has not entered for a certain period of time, we send the request to our backend. This time is in your hands, but if you optimize it, you will have a great balance between the user experience and the number of requests to the server.

Implementing useDebounce Hook

import { useEffect, useState } from "react";

// Part 1
const useDebounce = <T>(value: T, delay?: number): T => {
  // Part 2
  const [debouncedValue, setDebouncedValue] = useState<T>(value);

  // Part 3
  useEffect(() => {
    // Part 4
    const timeout = setTimeout(() => setDebouncedValue(value), delay || 500);

    // Part 5
    return () => {
      clearTimeout(timeout);
    };
  }, [value, delay]);

  // Part 5
  return debouncedValue;
};

// Part 6
export default useDebounce;
Enter fullscreen mode Exit fullscreen mode

Explanations

Part 1
We name our function using the use....() pattern and take the necessary arguments. The argument we receive here specifies the value as a generic argument so that you can use any kind of type here. Second argument is the delay amount that we talked about in the previous parts.

Part 2
We need to manage state internally in our hook. To do so, we used useState() hook.

Part 3
If the function's arguments change, the function should run again. That's why we use the useEffect builtin hook.

Part 4
By creating a timeout we will provide the required amount of wait. At the end of this period, we will update our state.

Part 5
The useEffect hook allows us to return a function that is used to run when component is unmounted. In this way, we prevent memory leaks by clearing our timeout when the component is unmounted.

Part 6
Exporting our custom hook.

Usage

Using the code below you can track the changes and enjoy your debounced value!

import React, { ChangeEvent, useState } from "react";
import { useDebounce } from "./hooks";

function App() {
  const [instantValue, setInstantValue] = useState<string>();
  const debouncedValue = useDebounce(instantValue, 500);

  return (
    <div>
      <input
        onChange={(e: ChangeEvent<HTMLInputElement>) =>
          setInstantValue(e.target.value)
        }
      />
      <p>Value: {instantValue}</p>
      <p>Debounced Value: {debouncedValue}</p>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Top comments (0)