DEV Community

Cover image for Throttling and Debouncing in ReactJS
Manish Kumar Sahu
Manish Kumar Sahu

Posted on

Throttling and Debouncing in ReactJS

Introduction

This article talks about how these two techniques can be applied to optimize website performance and covers how to make a optimized searchbar.

Suppose there is a program in which the programmer gives users to run any function, users can run them by firing events such as click, change, resize, scroll etc. So it's upto the user that how many times they want to run that function. The user can spam any number of times which is not good for the website, because those functions maybe going through heavy computations which may slow the website.

Let's consider an example in which whenever user types in searchbar, function is called which returns the total number of letter changes.
search

Now imagine, if there is a program in which for each change there is an function call which have heavy computations, this will slow down the website.

To prevent this kind of scenario, programmers use Throttling and Debouncing to limit the number of function calls so that even if the user spams, the performance will not be affected.

Implementation

These two techniques are not something which is provided by javascript itself.
These are the two techniques which uses web APIs i.e. setTimeout() and clearTimeout().

  • setTimeout() function takes a function and a time delay as parameters, call that function after the given delay and returns us a timerId which we can store.
  • clearTimeout() function takes that timerId as a parameter and clears the timeout set by the setTimeout() function.

Throttling

Throttling is a technique in which no matter how many times user fires the event, the function will run once in a given interval of time.

Suppose there is an API which fetches some data from the server.
Whenever the user searches something in the searchbar, then the function searches the letters typed by the user and returns the data accordingly. By using throttling here, the function will be called once in every 1 second.

Let's examine what is happening in the code.

  1. Whenever user types something, handleChange() function is called which contains a search() function.
  2. The search() function returns the data according to user typed letters, but it is not yet called.
  3. The search() function is passed to throttlingFunc() as a parameter with delay of 1 second.
  4. Inside throttlingFunc(), it checks if there is some value in timerId which is a global variable, if true it don't call setTimeout().
  5. If there is some value in timerId, it calls the setTimeout() which calls the search() and sets previous value of timerId as undefined.
  6. In this way the search() function will be called only after 1 seconds when user types something.

Debouncing

Debouncing is a technique in which no matter how many times user fires an event, the function will run only after a certain time after user stops firing events.

We will use the same API to fetch some data from the server and the same function which searches the data according to the letters typed by the user.But here, we will use debouncing and the function will be called after 1 second after user stops typing.

Let's examine what is happening in the code.

  1. Whenever user types something handleChange() function is called which contains a search() function.
  2. The search() function returns the data according to user typed letters, but it is not yet called.
  3. The search() function is passed to debouncingFunc() as a parameter with delay of 1 second.
  4. Inside debouncingFunc(), clearTimeout() clears the previous timeout by taking previous timerId value.
  5. Then calls setTimeout() which calls search() and gives new timerId.
  6. In this way the search() function will be called only after 1 seconds when user stops typing something.

Conclusion

In this article we understood how debouncing and throttling technique works while implementing it on a search function.

Hope you find it helpful 😄 .

References
https://www.telerik.com/blogs/debouncing-and-throttling-in-javascript

Cover image

Top comments (2)

Collapse
 
aminnairi profile image
Amin • Edited

Hi Manish and thanks for this interesting article,

You could also use a custom hook to create your own version of React.useCallback, but with throttling/debouncing.

import React from "react";

expprt const useThrottledCallback = (delay, dependencies, callback) => {
  const [timeoutIdentifier, setTimeoutIdentifier] = React.useState(null);

  return React.useCallback((...parameters) => {
    if (timeoutIdentifier !== null) {
      window.clearTimeout(timeoutIdentifier);
    }

    setTimeoutIdentifier(window.setTimeout(() => {
      setTimeoutIdentifier(null);
      callback(...parameters);
    }, delay));
  }, dependencies);
};
Enter fullscreen mode Exit fullscreen mode

Here is one example use-case scenario.

import {useThrottledCallback} from "./hooks/throttling";
import React from "react";

export const App = () => {
  const [search, setSearch] = React.useState("");
  const [result, setResult] = React.useState([]);

  const fetchResult = useThrottledCallback(1500, [search, setResult], () => {
    window.fetch(`https://jsonplaceholder.typicode.com/${search}`).then(response => {
      return response.json();
    }).then(newResult => {
      setResult(newResult);
    }).catch(() => {
      setResult([]);
    });
  });

  const onSearch = React.useCallback(event => {
    setSearch(event.target.value);
  }, [setSearch]);

  React.useEffect(() => {
    fetchResult();
  }, [search]);

  return (
    <div>
      <div>
        <label htmlFor="search">JSONPlaceholders endpoint</label>
        <input id="search" type="text" onInput={onSearch} value={search} />
      </div>
      <pre><code>{JSON.stringify(result, null, 2)}</code></pre>
    </div>
  );
};
Enter fullscreen mode Exit fullscreen mode

Seems like there is a NPM package that does that too, but I haven't got the occasion to test it out.

Collapse
 
trex777 profile image
Manish Kumar Sahu • Edited

Thanks, this is so much helpful, specially for reusability of the code, will definitely try this out.