I’m trying to use debounce in lodash to delay the onChange, see the code below.
import React, { useState, useEffect, useCallback } from "react";
import { TopBar } from "@shopify/polaris";
import { debounce } from "lodash";
function SearchBar() {
const [searchValue, setSearchValue] = useState("");
const handleSearchFieldChange = ((value:string) => {
setSearchValue(value);
});
const debounceLoadData = useCallback(debounce({searchValue} => fetchData, 1000), []);
useEffect(() => {
debounceLoadData();
console.log({searchValue})
}, [searchValue]);
function fetchData(value:string) {
console.log("searchValue " + value);
}
const searchFieldMarkup = (
<TopBar.SearchField
onChange={handleSearchFieldChange}
value={searchValue}
placeholder="Search Value"
/>
);
return <TopBar searchField={searchFieldMarkup} />;
}
In the beginning, I was tring to use searchValue
in fetchData function but seems because of scope, it failed to read it, it was always empty though the state had been updated.
As a result, I try to pass it in from the debounceLoadData
but I don’t know how I can do that as what in useCallback is a function invocation. How can I pass searchValue
in fetchData
inside debounce
.
3
Answers
I think you are getting confused by the functional
setState
syntax. Try this:lodash debounce takes in a function as the first argument. You can simply use
fetchData
as the function and pass on thesearchValue
todebounceLoadData
which will then be passed tofetchData
on invocationdebounce actually returns a function, think of debounce as being implemented like
So basically
debounceLoadData
is the returned function here andarguments passed to it i.e ...args
are being then passed to original function fetchData likefunc.apply(context, args)
Also
debounceLoadData
is created only once as the callback dependency is[]
, you whether you pass it to useEffect as a dependency of not will not make any difference.Please read this post for missing dependency warning
How to fix missing dependency warning when using useEffect React Hook?
I never like
useCallback
, it’s quite a confusing hook, and I always useuseMemo
instead since it totally covers whatuseCallback
can do (but not the other way around).Yet for your case I don’t think using lodash debounce is the best solution.
There’s a hidden risk that the final invocation of effect
fetchData
happens AFTER your component is unmounted. And iffetchData
contains some state mutation logic, that would raise an error of “Can’t call setState (or forceUpdate) on an unmounted component.” which is not destructive but not optimal either.I suggest manually debounce call using
setTimeout/clearTimeout
. It’s pretty simple: