reactjsreduxreact-redux

Accessing state in middleware in Redux


I have a middleware in my React/Redux app that looks like this:

export const myMiddleware = (store) => (next) => async (action) => {

   switch (action.type) {
      case types.SOME_ACTION:
      // Some logic here...
      break;
   }
}

I need to access the state here so that I can execute my logic this middleware is designed to handle.

I thought, because store is being passed into the middleware, I could access it but when I inspect store, I don't see the state at all. I do see a getState() function but when I used it, looks like it's getting me the initial state, not the current state with data in it.

Here's the store object I see when I inspect it: enter image description here

Here's my store and how I include the middleware in it:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '../reducers/root-reducer';
import { myMiddleware } from '../middleware/my-middleware';

export default function configureStore(initialState) {

    const store = createStore(
        rootReducer,
        initialState,
        applyMiddleware(thunk, myMiddleware)
    );

    return store;
}

How do I access state in my middleware?


Solution

  • You can get the updated state (after the current action) in the middleware, if you use getState() inside an async callback (signalR response for example). In this case, I've used setTimeout() to simulate an async action.

    Note:

    1. Although this works in theory, this is not a good idea. There is no guarantee that other actions haven't changed the state. In the example, you can see that the middleware shows the end state of both dispatched actions, for both actions.
    2. Regarding the discussion in the comments - simple state changes should be done in the reducer, and not in the middleware.

    const { createStore, applyMiddleware } = Redux;
    
    const DEMO_ACTION = 'DEMO_ACTION';
    
    const demoAction = (payload) => ({
      type: DEMO_ACTION,
      payload
    });
    
    const myMiddleware = ({ getState }) => (next) => async (action) => {
      setTimeout( // simulates an async action
        () => console.log(action.payload, getState())
      , 0);
       
      next(action);
    }
    
    const initialState = { data: [] };
    
    const rootReducer = (state = initialState, { type, payload }) => {
      switch(type) {
        case DEMO_ACTION:
          return {
            ...state,
            data: [...state.data, payload]
          };
      }
      
      return state;
    }
    
    const store = createStore(
      rootReducer,
      applyMiddleware(myMiddleware)
    );
    
    store.dispatch(demoAction('data1'));
    store.dispatch(demoAction('data2'));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0/redux.min.js"></script>