Here I will sort out the principles of Redux middleware. First I will say two concepts, Store enhancer and Dispatch enhancer. CreateStore (Reducer, initState, enhancer) — store enhancer — reducer — store The midddleware we usually use is dispatch enhancer.

The store enhancer function signature is :(createStore) =>(reducer, preloadedState) => store

Middeware function signature :({getState,dispatch}) => next => action => next(action) or other

__REDUX_DEVTOOLS_EXTENSION and applyMiddleware are both store Enhancer creater, which generates store Enhancer

Source code analysis:

export default function applyMiddleware(. middlewares) {
  return (createStore) = >( reducer, preloadedState) = > {
    const store = createStore(reducer, preloadedState)
    let dispatch = () = > {
      throw new Error(
        'Dispatching while constructing your middleware is not allowed. ' +
          'Other middleware would not be applied to this dispatch.')}const middlewareAPI = {
      getState: store.getState,
      dispatch: (action, ... args) = >dispatch(action, ... args) }// Step 1 (execute layer 1) : pass in unified getState, dispatch
    const chain = middlewares.map(middleware= > middleware(middlewareAPI))
    // Step 2 (compose) : generate (... args) => mid1(mid2(args))
    // Step 3 (execute)dispatch = compose(... chain)(store.dispatch)return {
      ...store,
      dispatch
    }
  }
}
// Here we take an example of two middleware: 1 >> 3 represents the three-tier structure of the middleware
// middleware signature :({getState,dispatch}) => next => action => f
function mid1_1 ({ dispatch, getState }) {
    return function mid1_2 (next) {
        return function mid1_3 (action) {
            console.log('Current Action1:', action)
            next(action)
            console.log('Changed store1:', dispatch, getState())
        }
    }
}
function mid2_1 ({ dispatch, getState }) {
    return function mid2_2 (next) {
        return function mid2_3 (action) {
            console.log('Current Action2:', action)
            next(action)
            console.log('Changed store2:', dispatch, getState())
        }
    }
}
// We'll focus on just three key steps in using Applymiddleware:

// Step 1: Const chain = middlewares.map(Middleware => Middleware API), each middleware gets the same getState and dispatch(temporarily false, Prevent dispatch from being called during creation), resulting in the following result
chain = [mid1_2, mid2_2]

// Step 2: Compose combines the above middleware arrays into one large function. The result of MID2-2, as the next parameter of MID1_2, is passed to the actual dispatch, the next of the last middleware is called Dispatch, and the next of the other middleware is returned by the later middleware
function (. args) {
  return mide1_2( mid2_2(args) )
}

// Step 3: Execute the above function, passing in the actual dispatch to get the final dispatch function
function mid1_3 (action) {
    console.log('Current Action1:', action)
    mid2_3(action)
    console.log('Changed store1:', getState())
}

// Mid1_3 and MID2_3Mid1_3:dispatchCompose (dispatch = compose(... Chain)(store.dispatch), changing the previous dispatch)getState: native store.getStatenext: becomes mid2_3 function MID2_3dispatch: The revamped DispatchgetState: native store.getStatenext: store.dispatch
Copy the code