I already visited this link and tried to follow some examples: Perform debounce in React.js
A bit of context: I'm building a search box that I want to deploy on NPM. Each time the user types, a prop function onSearch
is called. This to allow the programmers to fetch new data if they want.
The problem: each character typed will trigger onSearch, but that's not optimal, so I want to debounce that.
I wanted to do as one of the posts suggests:
import React, { useCallback } from "react";
import { debounce } from "lodash";
const handler = useCallback(debounce(someFunction, 2000), []);
const onChange = (event) => {
// perform any event related action here
handler();
};
My problem is that I need to pass an argument to "someFunction", and that argument is a state (a string):
const [searchString, setSearchString] = React.useState("");
After various attempts I finally found a solution. Remembering how I debounced the window resize event in the past, I followed more or less the same pattern. I did it by attaching an event listener to the window object and by adding a property to the event when dispatching it. It works, but is it a good solution? Is there a better way to achieve this?
React.useEffect( ()=> {
// This will contain the keyword searched when the event is dispatched (the value is stored in event.keyword)
// the only function dispatching the event is handleSetSearchString
// It's declared at this level so that it can be accessed from debounceDispatchToParent
let keyword = "";
// This function contains the onSearch function that will be debounced, inputDebounce is 200ms
const debounceDispatchToParent = debounce(() =>
onSearch(keyword, isCached("search-keyword-" + keyword)), inputDebounce);
// This function sets the keyword and calls debounceDispatchToParent
const eventListenerFunction = (e) => {
// the event has a property attached that contains the keyword
// store that value in keyword
keyword = e.keyword;
// call the function that will debounce onSearch
debounceDispatchToParent();
}
// Add the listener to the window object
window.addEventListener("dispatchToParent", eventListenerFunction, false);
// Clean up
return ()=> window.removeEventListener("dispacthToParent", eventListenerFunction);
}, []);
Then everytime the user types I call handleSetSearchString:
const handleSetSearchString = keyword => {
keyword = keyword.toLowerCase();
// If the string is longer than the minimum characters required to trigger a filter/search
if (keyword.length > minChars) {
// Here I create the event that contains the keyword
const event = new Event("dispatchToParent");
event.keyword = keyword;
window.dispatchEvent(event);
} else if (keyword.length === 0) {
// If the string is empty clear the results
setFilteredItems([]);
}
setSearchString(keyword);
};
Since both debounce
and useCallback
return a function you could just pass it directly.
const handler = useCallback(debounce(someFunction, 2000), []);
const onChange = (event) => {
// perform any event related action here
handler(argument1, argument2, ...args);
};