understand middleware

Simply put, middleware is a wrapper extension to the dispatch method of the store.
It provides a logical insertion point between the dispatch action and the moment the reducer is reached. You can use Redux middleware for logging, exception monitoring, talking to asynchronous APIs, routing, and more.
For details, please refer to the official document Middleware Middleware | Redux Chinese official website

Implementation

The common middleware in redux is written as

 function middleWare({ getState,dispatch }) {
  return next => action => {
       // xxx   
    return next(action)
   }
}

We can see that higher-order functions are used many times here, which looks very complicated. Let's analyze it step by step. For the convenience of marking, I will change the arrow function to the form of function declaration.

 function middleWare1({ getState, dispatch }) {
  return function nextHandle1(next) {
    return function actionHandle1(action) {
         //xxx
      return next(action)
    }
  }
}

Let's start to explain the specific usage scenarios of middleware nextHandle actionHandle

applyMiddleware

First of all, starting from the entrance, the common ways to use middleware are as follows
const store = createStore(reducer, applyMiddleware([thunk, logger]));
It can be seen that we wrap the middleware method in a layer through the applyMiddleware method. Then the process of processing middleware in the corresponding applyMiddleware method is:

 export default function applyMiddleware(
  ...middlewares: Middleware[]
) {
// 省略部分代码
  const middlewareAPI: MiddlewareAPI = {
    getState: store.getState,
    dispatch: (action, ...args) => dispatch(action, ...args)
  }
 // 调用middleware方法,并传参
  const chain = middlewares.map(middleware => middleware(middlewareAPI))
// 核心逻辑 将函数按序组合 compose(a, b, c)(dispatch) => a(b(c(dispatch)))
  dispatch = compose<typeof dispatch>(...chain)(store.dispatch)
  return {
    ...store,
    dispatch
  }
}
//简化compose函数实现
export default function compose(...funcs: Function[]) {
    return funcs.reduce(function(preFnA, itemFnB){
      return function (...args) {
          return preFnA(itemFnB(...args));
      }
  });
}

Through the above two lines of core code middlewares.map and dispatch = compose(xxx), we can analyze that middlewares is essentially rewriting and strengthening the original dispatch.
The corresponding middleWare1 function we wrote before is called here, then it becomes

 const chain = middlewares.map(middleware => middleware(middlewareAPI))
// middlewares在调用map方法后就成了
const chain = [nextHandle1, nextHandle2,...]

dispatch = compose<typeof dispatch>(...chain)(store.dispatch)
// chain中函数再次被compose组合,那么就成了
dispatch = actionHandle1(actionHandle2(actionHandle3(store.dispatch)))
dispatch = function actionHandle1(action){
   console.log('start1')
   const result = next(action);//此处的next函数即nextHandle2中的actionHandle2
   console.log('end1')
   return result 
}
function actionHandle2(action){
   console.log('start2')
   const result = next(action); //此处的next函数即actionHandle3
   console.log('end2')
   return result 
}
function actionHandle3(action){
   console.log('start3')
   const result = next(action); //此处的next函数即store.dispatch
   console.log('end3')
   return result 
}

In fact, in the middlewares calling process, it can be described by the onion model (aspect-oriented programming (AOP))
image.png
The above code will print start1=>start2=>start3=>end3=>end2=>end1 in sequence during execution.
The middle layer is the original store.dispatch(action), and the rest of the middleware that wraps it are all enhancements to dispatch

Summarize

At this point, the structure is relatively clear and can be summarized with a diagram

image.png


notself
134 声望13 粉丝