export { createStore, //建立一个state用来存储状态树 combineReducers, //合并reducer bindActionCreators, //将dispatch和action结合 applyMiddleware, //调度中间件来加强store,例如中间件redux-thunk等 compose //从右向左组合多个函数, compose(f, g, h)会返回(...args) => f(g(h(...args))) }
Redux源码结构和提供的API大致对应,以下:
utils——warning.js //console中打印warning信息要用到的
applyMiddleware.js
bindActionCreators.js
combineReducers.js
compose.js
createStore.js
index.js //export 上述定义的moduleredux
上面咱们看到了redux的API和源码结构,看的出来,warning.js和index.js不用解析,都看得懂,关键时其他的几个module,那咱们从最重要的createStore讲起。数组
export var ActionTypes = { INIT: '@@redux/INIT' } //首先定义了一个action类型,咱们知道更新state的惟一方法就是dispatch一个action,这个action是用 // 来初始化state的,后面会用到它
如今来看下createStore的大致结构app
//接收三个参数 //reducer为function。当dispatch一个action时,此函数接收action来更新state //preloadState初始化State //enhancer 为function。用来加强store, Redux 定义有applyMiddleware来加强store,后面会 //单独讲applyMiddleware export default function createStore(reducer, preloadedState, enhancer) { if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') { //若是只传了两个参数,而且第二个参数为函数,第二个参数会被看成enhancer enhancer = preloadedState preloadedState = undefined } if (typeof enhancer !== 'undefined') { if (typeof enhancer !== 'function') { //校验enhancer是否为函数,若是不是函数则抛出异常 throw new Error('Expected the enhancer to be a function.') } //若是enhancer存在且为函数,那么则返回以下调用,若是enhancer为applyMiddleware,那么调用则 //是applyMiddleware(middleware1, middleware2, middleware3...)(createStore)(reducer, preloadedState)。后面讲applyMiddleware再详细讲。 return enhancer(createStore)(reducer, preloadedState) } if (typeof reducer !== 'function') { //校验reducer是否为函数 throw new Error('Expected the reducer to be a function.') } var currentReducer = reducer //获得reducer var currentState = preloadedState //获得初始init,没有传递则为undefined var currentListeners = [] //定义一个数组用来存放listeners。就是一个函数数组,当state发生改变时,会循环执行这个数组里面的函数 var nextListeners = currentListeners //用来存储下一次的listeners数组。为何要有这个listeners数组呢?由于当state发生改变时,咱们根据 //上面的currentListeners来循环执行函数,可是在这执行这些函数时,函数内部可能取消或者添加订阅 //(state改变时,添加或者取消执行函数),这时若是直接操做currentListeners ,至关于在循环 //内部修改循环条件,执行瞬间就乱套了,有没有啊,有没有 var isDispatching = false //reducer函数是否正在执行的标识 function ensureCanMutateNextListeners() { //拷贝currentListeners一份为nextListeners,这样nextListeners的改变不会引发currentListeners的改变 //(上面解释过缘由啦) } function dispatch() { //触发action去执行reducer,更新state ..... } function subscribe() { //接收一个函数参数,订阅state的改变。当state改变时会执行这个函数 .... } function getState() { //获取state树 .... } function replaceReducer() { //替换reducer .... } function observable() { //没用,不解释(后面有解释) ...... } dispatch({ type: ActionTypes.INIT }) //执行dispatch函数,初始化state return { //真正的返回,执行createStore其实返回的就是这些东东 dispatch, //触发action去执行reducer,更新state subscribe, //订阅state改变,state改变时会执行subscribe的参数(本身定义的一个函数) getState, //获取state树 replaceReducer, //替换reducer [$$observable]: observable //redux内部用的,对咱们来讲没用(非要深究它写这是干吗的?咋跟 //我同样死脑筋呢,都说了没用啦。算了,仍是告诉你把,就是内部用的,在测试代码中会用到,感兴 //趣的能够去test目录下查看) } }
如今是否是感受明朗(懵逼)了许多,懵逼就对了,接下来咱们再来解析一下dispatch, subscribe等函数的具体实现,或许会让你明朗(更懵逼)起来
看了上面的大致结构,咱们明白如下这些就够了。
createStore是一个函数,它定义了一些变量(currentState, currentListeners等)及函数(dispatch, subscribe等),而且调用了dispatch,最后返回一个对象,该对象包含的就是dispatch和subscribe等函数。接下来咱们来解析这些函数。
createStore里面只调用了一个函数,那就是dispatch,那咱们就从这里开始讲起。异步
它是这样被调用的,有没有很熟悉。。。async
dispatch({ type: ActionTypes.INIT })
来看看dispatch的源码函数
function dispatch(action) { //校验action参数,必须为一个纯粹的对象。这也说明了,咱们不能直接在redux作异步请求,而是须要 //使用applyMiddleware去应用一些中间件。好比redux-thunk等 if (!isPlainObject(action)) { throw new Error( 'Actions must be plain objects. ' + 'Use custom middleware for async actions.' ) } //一样是校验参数,不解释,相信都能看懂 if (typeof action.type === 'undefined') { throw new Error( 'Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?' ) } //判断是否正在执行reducers函数,若是正在执行,此action不会触发,那有人就问题了,那是否是我 //的dispatch不会起做用,致使state没有更新,数据是错误的? 答案是state是不会有错。由于redux本 //身整个更新state的过程是同步的,从dipatch——>reducers——>state。因此这段代码意在你定义的 //reducers函数中不容许调用dispatch if (isDispatching) { throw new Error('Reducers may not dispatch actions.') } try { //设置标识为true,而且执行currentReducer,还记得吗?这个咱们经过参数获取到的一个函数,每每是我 //们调用combineReducers返回,combineReducers咱们后面解析 isDispatching = true //调用reducers函数 currentState = currentReducer(currentState, action) } finally { isDispatching = false } //调用全部订阅state改变的函数,这些函数就能够经过getState函数获取到最新的state值。订阅的函数 //从哪里来呢,从subscribe中来, 咱们后面来解析subscribe和getState var listeners = currentListeners = nextListeners for (var i = 0; i < listeners.length; i++) { listeners[i]() } return action }