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);
};
}
- Header
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;
- Search
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 box 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
- the result set does not represent the most recent input string, and
- 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