在使用redux-thunk进行异步action书写的时候,我常常好奇redux到底如何运做,让asyncAction成为可能react
为了探究,咱们必须看一下redux-thunk的源码了。幸运的是redux-thunk的源码不多。。。至于为何,下面立马讲解。es6
// redux-thunk source code 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;
从源码能够看出该中间件仅仅只是一个工厂函数,输出了一个嵌套工厂函数的工厂函数,那个最终参数带着next的返回函数,就是redux所须要适应的中间件。express
以es6箭头语法看来可能比较麻烦,咱们能够试着把这个代码直接转成es5的形式看看。redux
function createThunkMiddleware(extraArgument) { return function (storeOrFakeStore) { var dispatch = storeOrFakeStore.dispatch; var getState = storeOrFakeStore.getState; return function (next) { return function (action) { return action(dispatch, getState, extraArgument); } return next(action); } }; }
从这个源码能够看出,自己中间件是会接受当前store或者一个fakeStore(这个fakeStore可能仅仅只承载了store的两个api,dispatch和getState),并将dispatch和getState这两个store的方法传进可能执行异步操做的action函数里。这样,action完成异步操做之后,一样被赋予了dispatch的权利,就可以将状态经过action流转到下一个场景了。api
那同窗们又会问了,这个next是个啥?恩,其实这个next其实就是下一个要处理action的中间件,毕竟中间件是一个接着一个的对吧。若是你们写过koa或者express应该对这个next会熟悉不少。app
接下来咱们来看看react源码中的createStore模块是怎么应用中间件的。koa
applyMiddleware一样也是一个工厂,若是读者您用过redux中间件的话,你应该知道redux建立store是怎样建立的异步
const store = createStore( reducer, applyMiddleware(...middleware) )
如下是createStore的源码,咱们只看相关的一部分async
export default function createStore(reducer, preloadedState, enhancer) { if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer, preloadedState) } ... }
结合store的声明和使用,咱们能够知道redux的第三个参数能够接受一个叫作加强器的东西,若是存在加强器,则直接调用加强器方法,返回新的store并加强redux的功能。而使用中间件的时候,redux将存在的applyMiddleware工厂方法做为加强器应用在了redux上。函数
export default function applyMiddleware(...middlewares) { return (createStore) => (reducer, preloadedState, enhancer) => { const store = createStore(reducer, preloadedState, enhancer) let dispatch = store.dispatch let chain = [] const middlewareAPI = { getState: store.getState, dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } }
applyMiddleware工厂函数对传入的中间件进行了compose操做,使中间件互相之间呈嵌套的形式,这样在中间件里的next函数就能够next()执行下去了。。。新的dispatch会从第一个中间件开始触发,这样,在咱们调用store.dispatch的时候,就会将中间件走一遍了。
// compose函数 export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } // 若是存在多个中间件,直接使用reduce方法将各个中间件嵌套起来。 // 因而咱们在使用中间件的时候就要注意了,中间件本质是一个拦截操做 // 若是咱们有两个中间件对某一个类型的action前后作了拦截,咱们必须注意 // 在createStore的时候插入中间件的顺序,中间件方法的执行是有序的。 return funcs.reduce((a, b) => (...args) => a(b(...args))) }
怎么样,redux的源码简单吗?简单到同窗们也能本身开发中间件,如今你们本身也能够动手写本身的react中间件了。