I have created a debounced method inside my react component.
const [count, setCount] = useState(0);
const lazyLog = useCallback(
_.debounce(() => { console.log(count) }, 5000),
[count]
);
and I am calling it inside a useEffect, every time count
is updated:
useEffect(() => {
lazyLog();
}, [count])
The problem I am experiencing is that, as the lazyLog method is recreated on each render, the debounce
functionality is not applied correctly.
You can check this snack to test the code.
How can I fix the code? As the useCallback must include the dependency... I don't find any easy way to handle this... any ideas?
CodePudding user response:
State is stale as it's not included in the dependency array of useCallback
. Now if you add that the deBounce
will not work.
Solution is to use a ref
& hold a copy of the state in that. Then use that in the debounce
. (Codesandbox)
Also - [count]
should be []
in useCallback
.
const refValue = useRef(count);
const lazyLog = useCallback(
_.debounce(() => {
console.log("debounce", refValue.current);
}, 2000),
[] // empty
);
useEffect(() => {
refValue.current = count;
lazyLog();
}, [count]);
CodePudding user response:
I don't like the useDebounce
hook, described in the comments, at all, because I want to debounce the callback and not the value.
I think that, in order to avoid problem with the stale state, I will pass the counter as argument, instead of consuming it directly from my state.
export default function App() {
const [count, setCount] = useState(0);
const lazyLog = useCallback(
_.debounce((count) => { console.log(count); }, 5000),
[]
);
useEffect(() => {
lazyLog(count);
}, [count])
return (
<View>
<Text onPress={() => setCount(prevCount => prevCount 1)}>
Increase
</Text>
</View>
);
}
https://snack.expo.dev/67W9HnsRD
Not as clean as it could be but works fine with some minimal changes.