How to Debug Redux Middleware in React

Debugging Redux middleware in React is essential for tracking asynchronous actions, logging state changes, and diagnosing side effects in your application. This article provides a straightforward guide on how to debug Redux middleware using the Redux DevTools Extension, custom logging middleware, and native browser breakpoints to streamline your development workflow.

1. Use Redux DevTools Extension

The Redux DevTools Extension is the most powerful tool for debugging Redux state and middleware. It allows you to inspect every action dispatched, the state payload, and the difference in state before and after the middleware executes.

How to set it up:

To trace actions back to the middleware that triggered them, enable the action tracing option when configuring your Redux store:

import { configureStore } from '@reduxjs/store';
import rootReducer from './reducers';
import myMiddleware from './middleware';

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(myMiddleware),
  devTools: {
    trace: true, // Enables action tracing
    traceLimit: 25,
  },
});

How to use it:

  1. Open your browser’s Developer Tools and navigate to the Redux tab.
  2. Click on any dispatched action in the left panel.
  3. Select the Trace tab on the right side to see the exact stack trace and find which middleware or component dispatched the action.

2. Implement Custom Logging Middleware

Sometimes, writing a simple custom logging middleware is the fastest way to inspect values moving through the Redux pipeline. You can log the state before and after the middleware executes.

Here is how to write and insert a basic logger:

const loggerMiddleware = (store) => (next) => (action) => {
  console.group(`Action: ${action.type}`);
  console.log('Previous State:', store.getState());
  console.log('Action Payload:', action.payload);
  
  const result = next(action); // Passes action to the next middleware/reducer
  
  console.log('Next State:', store.getState());
  console.groupEnd();
  
  return result;
};

Add this logger to your store configuration to see real-time console logs of your action lifecycle.


3. Use Browser Breakpoints and the debugger Statement

For deep inspections of complex middleware (like Redux-Saga or Redux-Thunk), browser developer tools breakpoints are highly effective.

How to debug with breakpoints:

  1. Insert a debugger; statement directly inside your custom middleware code where the action is intercepted:
const myCustomMiddleware = (store) => (next) => (action) => {
  if (action.type === 'FETCH_DATA_TRIGGERED') {
    debugger; // Browser execution will pause here
    // Async logic or side effects
  }
  return next(action);
};
  1. Open your browser’s Developer Tools and trigger the action.
  2. The browser will pause execution at the debugger line.
  3. Use the Scope panel in your browser’s sources tab to inspect variables like store, next, action, and any local state. You can also step through the execution line-by-line to see exactly where the logic fails.