Debounce not working as expected react context, api call

  async-await, javascript, react-hooks, reactjs

used debounce function implementation without lodash from the gist credited below
utils.js

export const debounce = (fn, delay) => {
  let timer = null;
  return function (...args) {
      const context = this;
      timer && clearTimeout(timer);
      timer = setTimeout(() => {
          fn.apply(context, args);
      }, delay);
  };
}
import React, { useEffect, useRef, useState, useContext } from 'react';
import SearchContext from "../Search/context"
import { debounce } from "../../utils";

function Header() {
const [searchBox, setSearchBox] = useState(false)
const ref = useRef(null)
const inputRef = useRef(null)
const { searchInput, updateSearchInput } = useContext(SearchContext)
...
render(
...
<input className="searchInput"
 ref={inputRef}
 value={searchInput}
 onChange={(e) => debounce(updateSearchInput(e.currentTarget.value), 2000)}
 onBlur={() => setSearchBox(false)}
 type="text" maxLength="80" />
...
)

}
export default Header;
import React, { useContext, useRef, useEffect, useState, useCallback } from "react"
import { debounce } from "../../utils";
import searchContext from "../Search/context"
import { apiCallMethod} from "../../api"

const Search = () => {
   const context = useContext(searchContext)
   const [results, setResults] = useState(null)

// context.searchInput is the value of the input textbox provided by SearchContext.Provider

const fetchData = useCallback(async () => {
   // the input string is the query param for the api request  
   return await apiCallMethod(context.searchInput, null).then(response => {
   setResults(response.results)            

   })

}, [context]);

useEffect(() => {

   debounce(fetchData(), 2000)

   return () => setResults(null)
}, [fetchData])

render(...)
}
export default Search

A few things are happening in the components above

Since my application is fairly large, I am not directly making the API call from the html input onChange event.
I have a react context hook setup as searchContext that stores the text value entered in the input box

the same string is provided to the Search component through the context provider and it is called context.searchInput

In Search, there is a useEffect() that calls the Api method which returns the response data for the render.

However, the debounce is not working as expected. its not returning the correct results sometimes because

  1. the result set does not represent the most recent input string, and
  2. chrome devtools shows that it is firing excessive requests for substrings before debounce

I have tried to wrap debounce in onChange in the Header component, in the Search component, and both at the same time. I have also tried to increase the delay from 500 to 2000 but it does not help.

I can also drop the useCallback hook if there is a sideeffect. Appreciate the feedback

references

debounce implementation 1 https://gist.github.com/simonw/c29de00c20fde731243cbac8568a3d7f

debounce implementation 2 https://gist.github.com/sachinKumarGautam/6f6ce23fb70eec5d03e16b504b63ae2d

Source: Ask Javascript Questions

LEAVE A COMMENT