How to Use lodash debounce Correctly Inside React useEffect
I ran into a small but frustrating issue while trying to debounce a function inside React's useEffect(). The goal was simple: debounce a function call with lodash. So I installed the library and used it directly inside useEffect(), but the result was not what I expected.
What went wrong
The initial setup looked like this:
import { useState, useEffect } from "react";
import _ from "lodash";
useEffect(() => {
_.debounce(mx, 500); //防抖
}, [mc]);
Here, mx is a function. After applying debounce this way, not only did the debouncing fail to work, but mx itself also stopped running as expected. This is related to how useEffect() works.
After a few adjustments, I managed to get mx to execute again, but then another problem showed up: the value stored in the mc state was no longer staying in sync.
A working approach
The issue was resolved by changing the code to this:
useEffect(() => {
const debounceMX = _.debounce(() => {
mx();
console.log(mc);
}, 500);
debounceMX();
return () => {
debounceMX.cancel();
};
}, [mc]);
Why this works
In this version, the debounced function debounceMX is created inside useEffect(), and mc is included in the dependency array.
That means every time mc changes, useEffect() runs again, recreates debounceMX, and calls it with the latest state in scope. This avoids the problem where the function runs with outdated data.
The cleanup function is also important:
return () => {
debounceMX.cancel();
};
Calling debounceMX.cancel() when the effect is cleaned up ensures that any pending debounced execution is canceled when the component unmounts. It also helps prevent unexpected behavior or errors caused by delayed calls firing after the component lifecycle has moved on.
After several rounds of tweaking, this version finally fixed both issues at once: the debounce behavior started working properly, and the state value stayed synchronized.