Redux中间件源码剖析
redux中间件redux 是一个轻量级的数据流管理工具,主要解决了 component -> action -> reducer -> state 的单向数据流转问题。同时, redux 也提供了类似于 koa 和 express 的中间件(middleware)的概念,让我们可以介入数据从 redux 的中间件是通过第三方插件的方式实现,本身源码也不是很多,我们就从源码来解读 redux 的中间件机制。 首先来看我们是如何加载一个中间件的,以 redux-thunk 为例: import { createStore,applyMiddleware } from 'redux'; import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import reducers from './reducers.js'; let store = createStore( reducers,preloadedState,applyMiddleware(thunk) ); // ... 加载中间件有两个核心的方法: applyMiddleware首先看一下 import compose from './compose' export default function applyMiddleware(...middlewares) { return (createStore) => (reducer,enhancer) => { var store = createStore(reducer,enhancer) var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState,dispatch: (action) => dispatch(action) } chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) return { ...store,dispatch } } } 这就是 return (createStore) => (reducer,enhancer) => { ... } 这种写法同样是 return function (createStore) { return function (reducer,enhancer) { ... } }; 也就是说,负责加载中间件的 let store = createStore( reducers,defaultReducer,function (createStore) {...} // applyMiddleware(thunk) ); 接下来就来看看 createStore同样先来看一看 export default function createStore(reducer,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) } var currentReducer = reducer var currentState = preloadedState var currentListeners = [] var nextListeners = currentListeners var isDispatching = false function ensureCanMutateNextListeners() {...} function getState() {return currentState;} function subscribe(listener) {...} function dispatch(action) {...} function replaceReducer(nextReducer) {...} function observable() {...} dispatch({ type: ActionTypes.INIT }) return { dispatch,subscribe,getState,replaceReducer,[$$observable]: observable } }
逐块分析代码: 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) } 这块代码其实是 redux 中间件的核心入口,也是有无中间件处理流程的分叉口。如果我们注册了中间件,就会执行
// applyMiddleware(thunk) 返回的匿名函数 // 接收了 enhancer 传来的 createStore return function (createStore) { // 第一层匿名函数 // 接收了 enhancer(createStore) 传来的 reducer,preloadedState return function (reducer,enhancer) { // 第二层匿名函数 ... } }; 实际上, 第二层匿名函数同样拥有 reducer,enhancer 三个参数,也即: // 接收了 enhancer(createStore) 传来的 reducer,preloadedState return function (reducer,enhancer) { // 第二层匿名函数 var store = createStore(reducer,dispatch } } 那我们就来看一看这个匿名函数又做了什么事情。 var store = createStore(reducer,enhancer) 首先,第二层匿名函数又调了 return { dispatch,[$$observable]: observable } 接着往下看。 var dispatch = store.dispatch var chain = [] var middlewareAPI = { getState: store.getState,dispatch: (action) => dispatch(action) } 这些就是正常的变量赋值。继续往下。 chain = middlewares.map(middleware => middleware(middlewareAPI)) dispatch = compose(...chain)(store.dispatch) 别忘了,我们目前执行的第一层匿名函数和第二层匿名函数,都是在 export default function thunkMiddleware({ dispatch,getState }) { return function(next) { return function(action) { return typeof action === 'function' ? action(dispatch,getState) : next(action); } } } 是的, 我们再来看 export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } const last = funcs[funcs.length - 1] const rest = funcs.slice(0,-1) return function (...args) { rest.reduceRight(function(composed,f) { f(composed) },last(...args)) } }
/** * [description] * @param {[type]} previousValue [前一个项] * @param {[type]} currentValue [当前项] */ [0,1,2,3,4].reduceRight(function(previousValue,currentValue,index,array) { return previousValue + currentValue; },10); 以10为初始值,从数组的最后一位数字向左依次累加。所以结合上面的代码,可以知道 A = function () {}; B = function () {}; C = function () {}; chain = [A,B,C]; //dispatch = compose(...chain)(store.dispatch) dispatch = A(B(C(store.dispatch))) 明白了 function(next) { return function(action) { return typeof action === 'function' ? action(dispatch,getState) : next(action); } }(store.dispatch) 也就是说,其实 dispatch = function(action) { return typeof action === 'function' ? action(dispatch,getState) : next(action); } 我们结合 // 异步的 action function incrementAsync() { return dispatch => { setTimeout(() => { dispatch(increment()); },1000); }; } 触发上面异步 action 的方式是: dispatch(incrementAsync()); 回想上面的代码, return typeof action === 'function' ? action(dispatch,getState) : next(action); 当 那这是只有一个中间件的情况,有多个中间件时, 小结回到我们最开始讲到的,redux 的中间件其实就是让我们可以介入到 if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { throw new Error('Expected the enhancer to be a function.') } return enhancer(createStore)(reducer,preloadedState) // 进入中间件分支 } 当中间件分支处理完 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 使用XSLT以XML格式获取标记名称/属性名称
- c# – 如何将DataGridViewLinkColumn属性添加到DataGridVie
- c# – 如何在Windows Phone 8中使用ValueConverter作为Stat
- 依赖注入之Ninject框架
- Flex Chart有些总结
- Detailed Item Cost Report (XML) timed out waiting for t
- 聚合(Aggregation)和组合(Composition)的区别
- objective-c – 使用Objective C将位图转换为PNG或JPG
- Sqlite3-安装使用
- cocos2d_x_04_计时器_数据存储