Debouncing API calls in Redux middleware
We've heavily adopted Redux middleware at my job. IMO, it's the best place to put your side effects in a Redux-powered application.
Today I was trying to figure out how to debounce an API call in the middleware. It's attached to an auto-saving input and obviously we don't want an API call firing on every key stroke. We also don't want to debounce it in the components because we try to avoid adding business logic to our UI components if possible.
Well, I stumbled on a small gotcha and I figured I'd share.
The first thing I did was use lodash
to debounce the dispatch function inside of one of my middleware.
const updateQuantity = () => {
store.dispatch(
actions.putPartOrder({ quantity }));
};
const debouncedUpdate = debounce(updateQuantity, 500);
debouncedUpdate();
I went back to the UI and typed in the input a few times, and then I realized that I still had made one API call for every key stroke. Granted, it was debounced, but I'd say that's not much of an improvement.
After investigating further (thanks for the help Kurt Kemple) I learned the issue was the updateQuantity was being created on every action that was dispatched (keep in mind that all middleware actions fire every time a Redux action is dispatched in your app.
I refactored by moving the debounced function outside of the middleware into a helper function:
// debounce quantity api updates
const debouncedUpdate = debounce((store, quantity) => {
store.dispatch(actions.putPartOrder({ quantity }));
}, 500);
Then, I could just call this function inside my middleware and pass the store and quantity value in:
debouncedUpdate(store, quantity);
Now the function is only called once and all is well in performance land. 🙂
Have you used Redux middleware? What's your experience been with it? How have you debounced things like this? I'd love to hear.
J