I have a function that I'd like to debounce in my React project, using Lodash's debounce library.
The high level structure is like so (greatly simplified for purposes of this question):
callApiToSavetoDatabase()
once every 3 seconds.const autoSaveThing = useRef(debounce(() => {
callApiToSaveToDatabase();
}, 3000)).current;
const callApiToSaveToDatabase = useCallback(async () => {
console.log('Started API function');
setSomeState(true);
try {
const response = await apiCall(data);
} catch {
// failure handling
}
}, [ /* some dependencies */ ]);
What works:
callApiToSavetoDatabase()
is correctly only called once during the debounce period.What doesn't work:
console.log
line in callApiToSavetoDatabase()
but from debugging in the browser, the code quits out of callApiToSavetoDatabase()
as soon as I set state with setSomeState(true)
.Is there some limitation with setting state inside a useCallback function I'm hitting here?
It's worth noting that if I call callApiToSavetoDatabase()
directly it works perfectly.
The issue here ended up being that my callApiToSaveToDatabase()
function was both:
This combination cause a component re-render which subsequently halted my function.
The solution here was to move callApiToSaveToDatabase()
outside of the React component, and pass to it all the necessary state variables and setState function references it needed. An example of this is as follows:
// function that calls my API
const callApiToSaveToDatabase = async (someState,setSomeSTate) => {
setSomeState(true);
try {
const response = await apiCall(someState);
} catch {
// failure handling
}
};
// debounce wrapper around the API function above
const autoSaveThing = debounce((someState,setSomeState) => callApiToSaveToDatabase(someState,setSomeState), 3000));
// my React component
const myComponent = () => {
// some code
autoSaveThing(someState,setSomeState);
}