最近刚刚完成了毕业答辩,个人毕设内容是基于React系列技术栈开发的一个相似Instagram的Web App,戳此看看。开发完后,我惊奇的发现:咦,以前就据说有个叫作redux-thunk的东西,我怎么没用到?业务场景太简单了?因而大概研究了下。。git
关于redux-thunk的基本介绍,也许你能够先看看stackoverflow上面的介绍。我的理解:redux-thunk改写了dispatch API,使其具有接受一个函数做为参数的能力,从而达到middleware的效果,即在redux的dispatch action => reducer => store这个流程中,在action 被发起以后,到达 reducer 以前的扩展点,加入相关操做,好比发生请求、log信息等。github
以我本次毕设项目中,在redux流程中加入异步请求为例,为动态点赞功能部分代码实现:redux
//from action.js
const LIKE = (id) => ({
type: "LIKE",
id:id
})
reqLike({id:id}).then(res =>{ dispatch(LIKE(id))})
复制代码
能够看到,我在请求之后的回调函数中dispatch action去同步redux store中的状态。app
//from action.js
const LIKE = (id) => {
return function (dispatch,getState) {
reqLike({id:id}).then(res =>{
dispatch({
type: "LIKE",
id:id
})
})
}
}
dispatch(LIKE(id))
复制代码
改变之后,从功能层面上来讲,二者并没有差异,均可以知足业务场景需求。但除此以外咱们能够发现:异步
了解了redux-thunk的基本概念以及应用后,咱们一块儿看看源码加深下理解吧,源码十分精巧。ide
首先看到redux源码中applyMiddleware的部分,咱们将thunk做为参数传入以后,直接返回了一个函数,这个函数做为enhancer传入redux源码中的createStore函数中。函数
export default function applyMiddleware(...middlewares) {
//这个返回函数就是enhancer
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
}
}
}
复制代码
在redux源码中的createStore函数中,enhancer被执行,传入参数createStore,又紧接着执行其返回的函数,传入reducer和preloadedState.ui
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
复制代码
接下来,咱们进入applyMiddleware和thunk的关键部分,上面applyMiddleware接受的最初的(...middlewares)参数其实就是thunk,thunk会被执行,而且传入参数getState和dispatch.spa
//传入到thunk的参数
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
//在map中执行thunk
chain = middlewares.map(middleware =>middleware(middlewareAPI))
//从新改写dispatch
dispatch = compose(...chain)(store.dispatch)
复制代码
那么上面的chain是什么呢,咱们终于能够去看redux-thunk的源码了!code
function createThunkMiddleware(extraArgument) {
return function (_ref) {
var dispatch = _ref.dispatch,
getState = _ref.getState;
//这里返回的函数就是chain
return function (next) {
//这里返回的函数就是改写的dispatch
return function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
};
};
}
var thunk = createThunkMiddleware();
复制代码
从源码咱们能够看出,chain就是以next做为形参的匿名函数,至于compose只是不断传递每一个函数的返回值给下一个执行函数,而后依次去执行它全部传入的函数而已,它源码中的注释说的很清楚:For example, compose(f, g, h) is identical to doing (...args) => f(g(h(...args))).
咱们这里的chain只是一个函数而已,因此很简单,就是执行chain,而且传入store.dispatch做为next就行。
接下来,进入最后一步,改写了dispatch,最终变为:
function (action) {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
//next为以前传入的store.dispatch,即改写前的dispatch
return next(action);
};
复制代码
若是传入的参数是函数,则执行函数。不然仍是跟以前同样dispatch(PlainObject).
redux-thunk实现了相关异步流程内聚到redux的流程中,实现middleware的功能,也便于项目的开发与维护,避免冗余代码。而实现的方式即是改写redux中的dispatch API,使其能够除PlainObject外,接受一个函数做为参数。