I have gone through several posts but, none useful. So, in a small React project which displays all vegetable images. It also has search box which will fetch relevant vegetable card. I'm trying to implement debouncing
function but, not working as expected. Please follow the code below.
// useDeounce function called but, doesn't work
let newAllData = useCallback(useDebounce(searchData, 1000), []);
const getAllData = async () => {
try {
setLoading(true);
const { data } = await axios.get(
"https://mocki.io/v1/ffbc0f6f-342f-459d-93b4-5921f723b50e"
);
setLoading(false);
setNewData(data);
console.log("NEW DATA", data); // This gets called on every type of text
} catch (e) {
setError(e);
console.log(e);
}
};
useEffect(() => {
getAllData();
}, []);
const handleSearch = (value) => {
const event = value;
setSearchData(event);
};
const allData = useMemo(() => {
// the variable with debounce -> newAllData is used here
if (!newAllData) return newData;
console.log("NEW DATA HERE", newData);
return (
newData &&
newData?.filter(
(data) =>
(data.name.toLowerCase() && data.name.toLowerCase()).search(
newAllData.toLowerCase()
) !== -1 ||
(data.title.toLowerCase() &&
data.title.toLowerCase().search(newAllData.toLowerCase()) !== -1)
)
);
}, [searchData, newData]);
As you can see from above code, getAllData
fetches the data from API and is called in useEffect
, allData
is a memoized function which will prevent it from re-rendering, but, still on every tpye, API is called, hence with debouncing may reduce the calls and delay it. Please observe debouncing code.
const useDebounce = (val, delay) => {
const [debValue, setDebValue] = useState(val);
useEffect(() => {
const handler = setTimeout(() => {
setDebValue(val);
}, delay);
return () => {
clearTimeout(handler);
};
}, [val, delay]);
return debValue;
};
What could be the appropriate solution. Since, this is the major concern as API calls, may cost performance issue. Any suggestion highly appreciated.
CodeSandbox link: https://codesandbox.io/s/ecstatic-faraday-j85m9n
First of all remove the useCallback
that wraps your useDebounce
hook. Thats unnecessary.
let newAllData =useDebounce(searchData, 1000);
Second, update your useMemo
dependency array
const allData = useMemo(() => {
// the variable with debounce -> newAllData is used here
if (!newAllData) return newData;
console.log("NEW DATA HERE", newData);
return (
newData &&
newData?.filter(
(data) =>
(data.name.toLowerCase() && data.name.toLowerCase()).search(
newAllData.toLowerCase()
) !== -1 ||
(data.title.toLowerCase() &&
data.title.toLowerCase().search(newAllData.toLowerCase()) !== -1)
)
);
// Change the dependency here from [searchData, newData] to [newAllData, newData]
}, [newAllData, newData]);
Everything should work now as expected !