Debouncing in ReactJS

Debouncing in ReactJS

Have you ever been during a very situation where you’re typing in an input field and your computer or phone stops responding, or you’re scrolling through a webpage and it becomes unresponsive? This usually happens when there are event listeners attached to the actions being performed —like getting realtime results for a quest query as you type, or fetching new posts

Requirements

Search supported user input. Expected behaviour is, user enters the text and an api is termed to filter the data-list. If we use the keydown event, on every keystroke and event is triggered which successively fires an api call.

What is Debouncing

Debouncing, could also be a way where longer consuming processes don't seem to be fired frequently, decreasing function invocations. This may be done by wrapping the foremost function in an exceedingly debounce function and defining a timeout duration. If the identical function is invoked within the timeout duration, the previous instance is removed and a replacement instance is formed and also the most function only gets invoked, if the timeout runs its course. A simpler explanation is, say the duration is 5 seconds for the first instance and my value is X. I try to call the identical event within those 5 seconds, and now the value is XY. the first instance is removed and also the second instance replaces it. Now if the event is left for five seconds, the core function(api) gets executed.

Debouncing in React

Implementing debouncing during a functional component is different because the way React re-renders the functional component, the function state is lost. To avoid this state loss, either useRef or useCallback must be accustomed define the debounce callback. This will be required because the setTimout Instance isn't lost. I personally use useCallback as useRef returns a mutable object and useCallback helps with readability still. Before dive deep into debouncing, let's have a glance at an easy and normal example that implement an exploration box that allows users to seem something without clicking any button.

function App() {

  const handleDebouncing = e => {
    console.log('Data...')
  }

  return (
    <div className="App">
        <p> Search Data  </p>
        <input type='text' onChange={handleDebouncing} />
    </div>
  );
}

The issue is that handleDebouncing is very expensive, and this is bad practise as it will receive many requests in the same time.

Implementation

A debounce function is called after a specific amount of time passes since its last call.

function debounce(func, delay) {
    let timer;
    return function (...args) {
      clearTimeout(timer)
      timer = setTimeout(() => func(...args), delay)
    }

Here we are going to implement the debouncing for simple search of the car brand.

import { useEffect, useRef, useState } from "react";
import { getCarBrands } from "./data";
import "./styles.css";

export default function App() {
  const [data, setData] = useState(getCarBrands());
  let timerId = useRef();
  let [input, setInput] = useState("");

  useEffect(() => {
    clearTimeout(timerId.current);
    timerId.current = setTimeout(() => {
      setData(getCarBrands().filter((brand) => brand.name.includes(input)));
    }, 500);
  }, [input]);

  return (
    <div className="App">
      <div>
        <input
          value={input}
          placeholder={"Input Car Brand"}
          onChange={(e) => setInput(e.target.value)}
        />
      </div>
      <ul>
        {data.map((brand) => {
          return <li>{brand.name}</li>;
        })}
      </ul>
    </div>
  );
}

Here is the code sand box attached to play with the code

Real-life use cases

I'm currently working on an e-commerce app. In my app, for each item in the cart, the user can add different sizes and also increment or decrement the quantities of each size. The sizes and quantities are parsed into an object and stored in context before being sent to the server.

Conclusion

We’ve learned how to debounce functions in React, and we were able to fix our car brand filter problem with different implementations. So, go with the simplest one that works for your use case and your usecases.

Thanks for reading and I hope you found the article interesting.

If you found the article helpful, please like and share it. Follow me on Hashnode to get regular updates when I publish a new article. You can also connect with me on Twitter and check out my Github.

Also, I would love to hear any feedback from you.