Sam
Sam

Reputation: 30298

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?

Upvotes: 9

Views: 10247

Answers (2)

Peter L
Peter L

Reputation: 3343

Reading slice data from RootState

I wanted to supply an extra header when using RTK Query (middleware). Using Typescript, I navigated down the state object like so:

const accessToken = (getState() as RootState).appConfig.accessToken

(appConfig is a slice that I initialized at startup using login data)

Upvotes: 0

Ori Drori
Ori Drori

Reputation: 191986

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>

Upvotes: 5

Related Questions