Source code analysis of Redux — source code analysis of applymiddleware

Time:2021-5-7

Source code analysis of applymiddleware

Middleware mechanismstayreduxIt is powerful and convenient to usereduxWe can achieve logging, asynchronous call and many other very practical functions.reduxThe middleware is mainly through theapplyMiddlewareModule implementation. Now, let’s take a good look at the magic of this module.

About the use of middleware, students who do not understand also need to refer to Redux documents for learning.

Before we analyze the source code of middleware, we need to know one thing: where is the middleware modulereduxHow is the source code called? Only when we understand this problem can we know what each parameter represents.

The essence of middleware is asenhancerAnd there are many. So, it’s throughcreateStoreMethod passed toreduxInside of. In [create store source code analysis] (), there is such a piece of code:

if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
        throw new Error('Expected the enhancer to be a function.')
    }

    return enhancer(createStore)(reducer, preloadedState)
}

From this code, we can easily see that the middleware module is aHigher order function. Its function signature can be expressed as follows:

Const applymiddleware = (list of Middleware) = > (create store)) = > (reducer set, preloaded state)) = > {}

Now that we understand the above question, there is another question we need to know – that isreduxWhat is the form of middleware? Here, we choose the middleware to handle asynchronyredux-thunkSource code for you to explain( When I see the code, I just want to say, “I’m lying in a groove, I’m lying in a groove.”.

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) => next => action => {
    if (typeof action === 'function') {
      return action(dispatch, getState, extraArgument);
    }

    return next(action);
  };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

How do we use it in Redux?

createStore(reducers, applyMiddleware(thunk))

Here we arereduxHow to use middleware. Next, we will explain in detail:reduxHow to deal with middleware in source code. In order to help you understand better, let’s pull something.reduxAll the middleware in this paper follow certain specifications. Whether it is the official middleware or we need to write our own Middleware in the future, its function signature is certain. In other words, the basic format of middleware is the same, and the received parameters are the samereduxIt’s injected. Here we arereduxThe basic format of middleware is as follows

Const reduxmiddleware = ({dispatch, getstate} [simplified store]) = > (next [dispatch method of previous middleware]) = > (action [action object actually dispatched]) = > {}

Here, we can go deep into itreduxThe source code of middleware is as follows:

export default function applyMiddleware(...middlewares) {
  //Middlewares are a series of middleware functions that we pass to the applymiddlewarez function
  return (createStore) => (...args) => {
    //Createstore is the method used by Redux to create a store, args = [reducers, preloaded state]. The following sentence is to create a store object with the parameters we pass inside the middleware
    //Note: this block does not pass enhancer, so it returns the store object that we often use
    const store = createStore(...args)
    //Get the dispatch method of the store object
    let dispatch = store.dispatch
    //What is saved is the second layer function of middleware function
    let chain = []

    //Parameters of functions passed to the first layer of middleware,
    const middlewareAPI = {
      getState: store.getState,
      //Override the dispatch method, which is actually store. Dispatch (... Args)
      dispatch: (...args) => dispatch(...args)
    }

    /** 
     *I'll give you a detailed explanation
     *Suppose the middleware we pass to the applymiddleware function is
     * applyMiddleware(
     *      f1 => g1 => h1(...arg) => {},
     *      f2 => g2 => h2(...arg) => {}
     * )
     *After running the following line of code, the contents saved in the chain are
     * chain = [g1 => h1(...arg) => {}, g2 => h2(...arg) => {}]
     */
    
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    /**
     *After we pass chain into composition, according to our analysis of composition,
     *The result of compose (... Chain) (store. Dispatch) is as follows:
     * g1(h2(...arg)) => h1(...arg)
     * 
     *In other words, according to the above form, the following dispatch and H1 functions are the same. Therefore, the parameter of H1 is the action that we need to distribute. When we call dispatch, it is actually equivalent to calling H1 (action). Inside H1, the action is determined by the parameter of G1
     *In other words, H2 is used to distribute, so at this time, the action is passed to the interior of H2, and the parameters of H2 are distributed by the parameters of G2, that is, the actual incoming store. Dispatch. In this way, the actions are imported and exported layer by layer, forming our powerful middleware mechanism.
     */
    dispatch = compose(...chain)(store.dispatch)

    //It also returns a store object
    return {
      ...store,
      //This dispatch is actually a circular function composed of which functions at the bottom layer (the third layer) of each middleware
      dispatch
    }
  }
}

That’s rightapplyMiddlewareAn overall interpretation of the source code, the level is limited, welcome to brick. The following source code interpretation and test examples can focus on:Redux source code interpretation warehouse