I'm attempting to use lodash's debouncer method in a react function component. When I attempt to create the debouncer-wrapped callback, I receive
TypeError: Expected a function
I've attempted to work through three or four examples, but none of them work within my existing app. The latest attempt I'm working through is here.
const [userQuery, setUserQuery] = useState("")
const [deb, setDeb] = useState("");
const updateQuery = () => {
setDeb(userQuery)
};
const delayedQuery = useCallback(() => debounce(updateQuery, 500), [userQuery]);
const onChange = e => {
setUserQuery(e.target.value);
};
useEffect(() => {
delayedQuery();
// Cancel the debounce on useEffect cleanup.
return delayedQuery.cancel;
}, [userQuery, delayedQuery]);
The code functions overall without the debounce wrapper and related return in the useEffect (without any debouncing, of course).
I'm at a level of modestly comfortable with React so have a lot of gaps in my deeper understanding that could be the problem.
CodePudding user response:
When you call delayedQuery() you return the debounced function, and not the result of calling the debounced function. Since debounce returns a debounced function with the cancel method, and useCallback accepts a function, define delayedQuery like this:
const delayedQuery = useCallback(debounce(updateQuery, 500), []);
CodePudding user response:
I assume the mentioned TypeError was thrown during the useEffect, since you have not provided any Stack Trace.
Edit thanks to the comment and suggestion by @Ori Drori:
Change the delayedQuery to the following:
const delayedQuery = useCallback(debounce(updateQuery, 500), []);
This way, you will have a memoized value of your debounced method, which will be a callback anyway, with the available cancel property.
Previous Answer (just for reference):
Then you can try changing your useEffect to the following:
useEffect(() => {
const query = delayedQuery();
query();
// Cancel the denounce on useEffect cleanup
return query.cancel;
}, [userQuery, delayedQuery]);
Explanation
You can have a look at the different types of your methods and callbacks. I‘ll start at the beginning:
useCallbacksimply takes any method and returns a new method, which will simply invoke the provided method. It will match the signature of the provided method.- The provided callback, in turn, is a simple arrow function, which returns a
debounced method. - The
debounced method, according to the lodash docs, can either be called immediately,canceled orflushed.
This leads us to the following in your useEffect:
delayedQueryis a callback.- You call
delayedQuery(), where the hook invokes the arrow function. - The arrow function invokes the
debounceand returns its value — the debouncedupdateQuery! - BUT: at this point, your query has not yet been invoked! Moreover, since only the return type of your callback is a debounced function, there is no property
delayedQuery.cancel. - And because
delayedQuery.cancel == undefined, you get the mentionedTypeError.
