applyMiddleware.js is used to generate the middleware chain that action passes through according to the middleware. Let"s first take a look at the implementation of an incorrect version:
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, initialState, enhancer) => {
var store = createStore(reducer, initialState, enhancer)
var chain = []
var middlewareAPI = {
getState: store.getState,
dispatch: store.dispatch
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
var dispatch = compose(...chain)(store.dispatch) //compose(f, g, h)
//...args=>f(g(h(args)))
return {
...store,
dispatch
}
}
there is no problem with the above normal, but the problem arises when our middleware needs to use the dispatch function directly. For example, the middleware redux-thunk, which is commonly used to send asynchronous action, requires the use of dispatch: in asynchronous action
export function fetchPosts(subreddit) {
return function (dispatch) {
dispatch(requestPosts(subreddit))
return fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then(
response => response.json(),
error => console.log("An error occured.", error)
)
.then(json =>
dispatch(receivePosts(subreddit, json))
)
}
}
the dispatch, used by fetchPosts is passed from redux-thunk, pointing to the fact that the dispatch, in the middlewareAPI object is actually equal to store.dispatch. when executing dispatch (requestPosts (subreddit)), the action goes directly to the last step of processing, skipping the processing of other middleware after redux-thunk middleware, which is obviously inappropriate. [1] what we want is that the action will still start with the outermost middleware and go through each layer of middleware from the outside to the inside. Therefore, the dispatch function used here cannot be equal to store.dispatch, should be equal to compose (.chain) (store.dispatch). Only in this way can the sent action be processed by each layer of middleware. [2] now the problem arises: chain = middlewares.map (middleware = > middleware (middlewareAPI)) needs to use the dispatch function returned by dispatch = compose (.chain) (store.dispatch), while the execution of dispatch = compose (.chain) (store.dispatch) depends on the execution result of chain = middlewares.map (middleware = > middleware (middlewareAPI), so we are in an endless loop. [3]
I just learned redux, to find out the internal ideal. There are many wonderful operations implemented internally, such as changing the dispatch: store.dispatchg
inside middlewareAPI
to dispatch: (.args) = > dispatch (.args)
. Through the closure referencing the external dispatch variable, there is a question about this operation:
[1]: why did action go straight to the last step?
[2]: why does the dispatch function need to be equal to the function returned by compose (.chain) (store.dispatch)
? isn"t dispatch the store.dispatch that has been passed into the top-level element in the process
[3]: how to form an endless loop? please specify
original link