Reputation: 4050
I'm trying to write custom hooks but I'm facing an issue whenever I want function as arguments.
I want to write a useDebouce hook; From example around the web I ended up with this:
import { useCallback, useEffect } from 'react';
import debounce from 'lodash/debounce';
const useDebounce = (fn, time, options) => {
useEffect(() => console.log('reset'), [fn, time, options]);
return useCallback(debounce(fn, time, options), [fn, time, options]);
};
I want to reset whenever an argument change.
However if I use it like this:
const randomComponent = () => {
const doSomething = useDebounce(() => console.log('test'), 500, {maxWait: 1000});
// ...
};
Every time my component renders the function and object reference change (1st and 3rd arguments), which means I end up creating a new debounced function everytime. So the debounce behavior doesn't work.
What is the best way to deal with callback references changing at every render ?
Upvotes: 3
Views: 275
Reputation: 53984
There is no way out, the user must make sure it has the same reference:
import { useCallback, useEffect } from 'react';
import debounce from 'lodash/debounce';
const useDebounce = (fn, time, options) => {
useEffect(() => {
// Don't forget to cancel the debounce
return () => debounce(fn).cancel();
}, [fn, time, options]);
return useCallback(debounce(fn, time, options), [fn, time, options]);
};
const log = () => console.log('test');
const maxWait = { maxWait: 1000 };
// Outer scope holds the same reference
const randomComponent = () => {
const doSomething = useDebounce(log, 500, maxWait);
};
// Or memoization, more usefull with state
const randomComponent = () => {
const log = useCallback(() => console.log('test'), []);
const maxWait = useMemo(() => ({ maxWait: 1000 }), []);
const doSomething = useDebounce(log, 500, maxWait);
};
Also, if you don't want to deal with references, the user might provide a comparison function. May suggest trying another approach:
// Something like that (not tested)
const useDebounce = (fn, time, options, comp) => {
const debounceRef = useRef(debounce(fn, time, options));
if (comp(fn, time, options)) {
debounce(debounceRef.current).cancel();
debounceRef.current = debounce(fn, time, options);
}
return useCallback(debounceRef.current, []);
};
Upvotes: 1