Blog>
Snippets

Debouncing Input with Redux Middleware

Demonstrate the use of custom middleware to debounce an input field action to prevent rapid firing of actions in a Redux-managed state.
const debounceMiddleware = ({ dispatch, getState }) => next => action => {
  if (action.meta && action.meta.debounce) {
    const { key, time } = action.meta.debounce;
    if (time) {
      if (debounceMiddleware.debounceTimers[key]) {
        clearTimeout(debounceMiddleware.debounceTimers[key]);
      }
      debounceMiddleware.debounceTimers[key] = setTimeout(
        () => next(action),
        time
      );
    }
  } else {
    return next(action);
  }
};
debounceMiddleware.debounceTimers = {};

// ... Often useful to combine with reducers, actions, and other middlewares ...
Custom Redux middleware named debounceMiddleware which accepts actions with a meta field specifying debounce details. It uses setTimeout to delay action dispatching.
// Your actions.js
export const setInputValue = (value) => ({
  type: 'SET_INPUT_VALUE',
  payload: value,
  meta: { debounce: { key: 'setInputValue', time: 500 } }
});
Defines an action creator with a debounce configuration in the meta object. The 'SET_INPUT_VALUE' action will be debounced for 500ms.
// Your Component.jsx (React example)
import React, { useState } from 'react';
import { useDispatch } from 'react-redux';
import { setInputValue } from './actions';

const SearchInput = () => {
  const dispatch = useDispatch();
  const [inputValue, setInput] = useState('');

  const handleInputChange = (e) => {
    const value = e.target.value;
    setInput(value);
    dispatch(setInputValue(value));
  };

  return (
    <input
      value={inputValue}
      onChange={handleInputChange}
      placeholder='Type to search...'
    />
  );
};

export default SearchInput;
A React component demonstrating how to use the 'setInputValue' action with the debounce middleware in a controlled input.
/* Your reducer.js */
export const inputReducer = (state = '', action) => {
  switch (action.type) {
    case 'SET_INPUT_VALUE':
      return action.payload;
    default:
      return state;
  }
};
A Redux reducer that responds to the 'SET_INPUT_VALUE' action to update state based on the debounced input value.
/* Your applyMiddleware call in the Redux store setup */
import { createStore, applyMiddleware } from 'redux';
import rootReducer from './reducers';
import { composeWithDevTools } from 'redux-devtools-extension';

const store = createStore(
  rootReducer,
  composeWithDevTools(
    applyMiddleware(debounceMiddleware)
    // ...add other middlewares here
  )
);

export default store;
Sets up the Redux store and applies the debounceMiddleware created earlier.
/* Your HTML */
<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <title>Debounced Input Example</title>
  <script src='/path_to_your_compiled_js_bundle.js' defer></script>
</head>
<body>
  <div id='app'></div>
</body>
</html>
The HTML markup with a script tag to include the compiled JavaScript bundle where the React component and Redux store are defined.
/* Your CSS */
input {
  padding: 10px;
  margin: 10px;
  border: 1px solid #ccc;
  border-radius: 4px;
}
Basic CSS for styling the input element.