Redux很早前看过源码,不得不说Redux是一个有用的架构,接触过Redux对于之后理解React-Redux有很大的帮助。最近学习了一段时间后打算重新学习下,一方面为了总结和归纳,另一方面分享给大家,如果有什么不足之处希望各位大牛的纠错和指正。本文主要包含如下几个分析点:
- applyMiddleware
- compose
- thunk中间件
// 该文件的核心函数部分共传入了三个参数// reducer, preloadedState, enhancerfunction createStore(reducer, preloadedState, enhancer){ ... if (typeof enhancer !== 'undefined') { return enhancer(createStore)(reducer, preloadedState) } ...}复制代码
createStore
方法的作用是用来创建一个仓库来存放state,subscribe,reducer以及dispatch,state用来存放数据的地方,通过store.getState()来获取;subscribe用来加入监听函数,当页面数据改变的时候会进行触发,dispatch用来派发action,根据不同的类型匹配不同的reducer,继而进行state数据的更新,具体可以参考阮一峰老师的博客 。
其中enhancer
函数的作用顾名思义就是用来扩展加强的,这个函数的存在使得可以随意的加入早就想要的中间件,从而更加方便快捷,这里的加强函数主要是applyMiddleware
。
applyMiddleware
这里使用连续箭头函数,简单明了更重要的一点是形成了闭包,闭包的存在使得内部的变量可以很自由的访问外部被多个return嵌套的变量, 从而使得每个中间件都获得middlewareAPI参数,引用外部的dispatch变量,这样避免了如果存在一个中间件修改了dispatch导致后面一系列的问题。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) // 通过闭包引用外部的dispatch变量 } // 将middlewareAPI传入中间件,使得每个中间件都获得{getState,dispatch}参数,而由于闭包的原因,我们就可以在中间件当中获取最新的store以及引用外部更新的dispatch变量。 // @return 返回包含(next) => (action) => {....}的数组 chain = middlewares.map(middleware => middleware(middlewareAPI)) // 创建增强功能的dispatch dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } }}复制代码
thunk中间件
以thunk中间件为例,当需要派发的action是异步函数而不是对象的时候需要这个中间件,则此时chain即为 [(next)=>(action)=>{...}, ....], 如果action为函数则直接执行该函数,并且传入 dispatch和 getSate这两个参数,否则执行next方法直到最后next函数为dispatch进行action派发。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;复制代码
compose
理解compose方法首先需要了解reduce,reduce()方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值,所以最终的形式是a(b(c(d...(...args))))
。
export default function compose(...funcs) { if (funcs.length === 0) { return arg => arg } if (funcs.length === 1) { return funcs[0] } return funcs.reduce((a, b) => (...args) => a(b(...args)))}复制代码
之前chain返回包含(next) => {...}的thunk,logger中间件数组,从而得到a_middleware方法里的next方法就是b_middleware,b_middleware方法里的next方法是c_middleware,以此类推,根据applyMiddleware.js
中compose(...chain)(store.dispatch)
以及chain返回值
可以知道, 最后的next参数是dispatch,大概步骤如下:
- 第一步:当我们把store.dispatch传入c_middleware时,这时就把store.dispatch传给了 c_middleware的next变量,返回一个
(action)=>{next=store.dispatch}
[1]函数; - 第二步:接下来就是把
[1]
传给b_middleware的中间件的next,这时候中间件b_middleware内部的next就变成(action)=>{[1]}
[2], 当执行b_middleware的时候,会进入c_middleware; - 第三步:接下来就是把
[2]
的结果传递给a_middleware, (action)=>(action)=>{[1]}传递给a-middleware的next变量,当执行a_middleware的时候会进入b_middleware。
从下面大概例子可以看出disatch: (...args) => dispatch(...args)
的好处,dispatch随时随地随着dispatch = compose(...chain)(store.dispatch)
更新而更新,从而当传入为方法的时候,也不会忽略其他中间件,再次dispatch的时候会流过所有thunk之后的中间件。
1.a_middleware(b_middleware){ ... b_middleware = (action) => (action) => {store.dispatch函数} return (action) => b_middleware(action) ...}dispatch = (action) => { if (typeof action === 'function') { return action(dispatch, getState, extraArgument); } return b_middleware(action)}2.b_middleware(c_middleware){ ... c_middleware = (action) => {store.dispatch函数} return (action) => c_middleware(action) ...}dispatch = (action) => { return c_middleware(action)}3.c_middleware(store.dispatch){ return (action) => {store.dispatch函数}}dispatch = (action) => {store.dispatch函数}复制代码
总结
1.首先将store.getState
和store.dispatch
通过闭包的方式使得中间件可以访问;
2.其次,通过compose
函数操作,对next进行赋值,使得中间件按顺序依次执行;
3.最后,返回一个dispatch函数
,可以通过传入action参数,使得中间件按顺序依次执行,如果action为函数则直接执行该函数,并且传入dispatch和getSate参数。
总之使用redux进行状态管理极大地提高了工作效率,让数据更好地被管理。