redux源码分析

总体概览:

主要四个大点,

1.createStore主要三个api,

2.compose reduce applyMiddleware(thunk)

3.bindActionCreators参数间互执行

4.combineReducers维持state树,遍历返回分支state,最终return整体state

一.createStore.js
return {
dispatch, //唯一一个可以改变 state 的哈按时
subscribe, //订阅一个状态改变后,要触发的监听函数
getState, // 获取 store 里的 state
replaceReducer, //Redux热加载的时候可以替换 Reducer
[$$observable]: observable //对象的私有属性,供内部使用
}
getState读取里面的变量currentState,此处目测是个闭包的用法;函数最终return上面的几个API,他们可以访问内部私有变量
其中,dispatch内部会执行reducer 以及遍历回调函数listeners
subscribe是监听,push回调函数的

官方解释:
dispatch:分发 Action 到对应的 Reducer后,根据 Reducer 逻辑更改store 中的 state,之后触发 subscribe的 listener
getState:获取当前store 中的 state 数据,
subscribe: 注册 listener,在 state 变化时触发,
replaceReducer:替换 Reducer,修改 state 变化逻辑,替换后会初始化一下state不是很常用。

二.compose.js和applyMiddleware.js
(先解释compose的reduce数组方法,然后解释applyMiddleware调用中间件,达到增强dispatch的目的)
compose.js内部调用的是数组的reduce,let sum = [1,2,3,4,5].reduce((a,b)=>a+b);
好了,我就当作你已经理解了reduce方法,那么redux这里的compose也就不难理解了,它巧妙的地方在于数组的每个元素都是函数,callback返回一个复合函数作为previousValue,在reduce方法执行完之后,也就返回了一个将整个数组中所有函数串式调用的一个函数。 然后applyMiddleware里调用了compose,thunk中间件作为参数传给applyMiddleware函数的执行结果就是一个enhancer。
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;


代码非常短,可以看到最终export了一个接受{ dispatch, getState }作为参数的function thunk,这个thunk方法也就是传给applyMiddleware方法的参数,此时的middlewares只有thunk一个方法,那么applyMiddleware中的chain也就很显然的是执行了thunk方法后返回的结果,我们再看redux-thunk的代码,返回了一个接受next作为参数的方法A! applyMiddleware的下一行,dispatch = compose(...chain)(store.dispatch),chain只有一个function,所以这里可以忽略compose,那么这一句就是将store.dispatch 作为next参数传给了刚才的方法A,终于,方法A返回了我们熟悉的dispatch方法。有点绕,但是我相信只要你静下心缕一缕,是可以弄明白的,然后你就会体会到函数式编程的魅力!
但是注意,此时的dispatch方法还是原来的dispatch方法吗?
人面不知何处去,桃花依旧笑春风。它已经不是原来的它了。经过thunk方法的包装,早已物是人非。
我们来看一下redux-thunk的代码,第三行之后的4行,如果dispatch方法接受的参数不是一个function,那么这个dispatch就和普通的dispatch没什么不同,但如果此时的action是一个方法,那么就会执行此方法,且第一个参数是store.dispatch。
这意味着我们的action创建函数不再只能创建一个包含type的Object,而可以是一个方法。你可能会问有什么用呢?当你在action中需要一个异步操作,并需要在回调中改变state的状态的时候,这就是一个绝佳的解决方案。
所以说,applyMiddleware实际上做了一件事,就是根据外部函数(中间件函数)包装原来的dispatch函数,然后将新的dispatch函数暴露出去。
三.bindActionCreators.js

bindActionCreators函数用法是用在mapDispatchToProps里return的对象里面:
return {
getUserInfo : bindActionCreators(getUserInfo,dispatch)

}

bindActionCreator作用就是让它里面的参数互相作用执行哈哈哈,就是dispatch(getUserInfo());


bindActionCreators函数就是遍历每个actionCreators(必须为object类型),让里面的每个actionCreator 都被bindActionCreator函数执行一遍

四.combineReducers

内部最后会 return 一个combination(state = {}, action) 函数,(这个函数初始化state也是空?这个action目测在后期遍历的时候,每个分支reducer都是传的这个action,这就验证了之前自己的观点。)这个函数内会遍历finalReducerKeys(这个就是我们调用combineReducers时候传进去的参数的过滤版,只过滤出键值为函数的版本)
combination内部有如下代码:函数返回值是一个state树
如下代码遍历之后会更新这个state树


let hasChanged = false;
const nextState = {} ;//下一个state树
//遍历所有reducers,然后将每个reducer返回的state组合起来生成一个大的状态树,所以任何action,redux都会遍历所有的reducer
for (let i = 0; i < finalReducerKeys.length; i++) {
const key = finalReducerKeys[i] ;
const reducer = finalReducers[key] ;
const previousStateForKey = state[key] ;
const nextStateForKey = reducer(previousStateForKey, action) ;
//这两句话说明 真的单个reducer更改的是 这单个state[key]下的分支state,证实了自己的猜想

//如果此reducer返回的新的state是undefined,抛出异常
if (typeof nextStateForKey === 'undefined') {
const errorMessage = getUndefinedStateErrorMessage(key, action) throw new Error(errorMessage)
}
nextState[key] = nextStateForKey;
hasChanged = hasChanged || nextStateForKey !== previousStateForKey ;
} //如果当前action对应的reducer方法执行完后,该处数据没有变化,则返回原来的流程树

return hasChanged ? nextState : state;

posted @ 2018-07-02 18:35  River89397380  阅读(77)  评论(0)    收藏  举报