深度剖析github上15.1k Star项目:redux-thunk
日益忙碌的一周又过去了,是时候开始每周一次的总结复盘了,今天笔者就来剖析一下github中star数15.1k的开源项目redux-thunk。
作为一名React方向的前端工程师,不管是被面试还是面试别人,大部分都会说起redux-thunk的实现原理,因为它非常经典且有用,而且代码量少的感人,只有短短12行代码,却能解决React开发中同一个函数支持多dispatch和异步action的问题(虽然这完全依赖于redux的中间件机制(Middleware))。
接下来笔者将从:
Redux的工作机制
中间件实现原理
redux-thunk源码实现
这三个方面来带大家彻底掌握redux-thunk源码,从而对redux有更深入的了解和应用。如果大家对react-redux-redux-thunk实战感兴趣的,读完之后可以移步笔者的《彻底掌握redux》之开发一个任务管理平台
正文
redux解决的真正问题是React组件间的状态共享和状态管理问题,通过以上的6个核心api我们便能管理复杂的状态,并能监听和追溯状态的改动。机制笔者总结如下:
redux工作机理基本了解之后,我们先看看一个实际的例子:
import actionType from './actionType'
class Actions {
static start() {
return {
type: actionType.CREATE_TODO_DOING
}
}
static ok(data, cb) {
cb && 'function' === typeof cb && cb(data);
return {
type: actionType.CREATE_TODO_SUCCESS,
payload: data
}
}
static fail(data, cb) {
cb && 'function' === typeof cb && cb(data);
return {
type: actionType.CREATE_TODO_FAILURE,
payload: data
}
}
}
到这一步我们仍然不能直接进入redux-thunk的源码分析,因为我们还是不清楚如何解决上述步骤,因为我们还没有了解redux的中间件机制。
redux中间件机制
import { createStore, applyMiddleware } from 'redux';
import reducers from './reducers';
const middlewares = applyMiddleware(middleware1, middleware2);
const store = createStore(reducers, middlewares);
所以说redux-thunk是被传入applyMiddleware方法中作为参数使用的,不难猜到applyMiddleware方法中一定有遍历执行参数的逻辑,我们来看看applyMiddleware的核心源码:
export default function applyMiddleware(...middlewares) {
return function enhancer(createStore) {
return function enhancedCreateStore(...args) {
const store = createStore(...args)
let dispatch = () => {
thrownewError('此处省略n个字...')
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(function(middleware) {
return middleware(middlewareAPI)
})
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch,
}
}
}
}
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce(function(a, b) {
return function (...args) {
return a(b(...args))
}
})
}
在掌握了redux中间件实现原理之后, 我们再来看redux-thunk源码就非常容易理解了。
redux-thunk源码分析
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也就是第二次调用时的store.dispatch, 为了实现同一函数内能执行多次dispatch,我们会判断如果action为函数,则执行action本身并把必要参数传递给它,否则则直接触发dispatch,这样我们就实现了支持action为函数并且支持异步多dispatch的功能了,读到这还是非常感叹其设计的优雅和简洁,不经让笔者感叹:学好函数式,走遍天下都不怕!
最后笔者准备了一个基于React+redux+redux-thunk的实战项目,github地址:
https://github.com/MrXujiang/redux_OA
感兴趣的可以学习参考一下。
最后
如果想学习更多H5游戏, webpack,node,gulp,css3,javascript,nodeJS,canvas数据可视化等前端知识和实战,欢迎在公号《趣谈前端》加入我们的技术群一起学习讨论,共同探索前端的边界。