简体   繁体   中英

Debounce with useCallback in React

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):

  1. I have a function that can be called multiple times, but should only trigger callApiToSavetoDatabase() once every 3 seconds.
const autoSaveThing = useRef(debounce(() => {
    callApiToSaveToDatabase();
}, 3000)).current;
  1. This API calls an asynchronous function that sets react State and calls an API.
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:

  • We hit the 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:

  1. Inside my React component and
  2. Also setting React state

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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM