Redux createStore源码学习

Redux API 和 Redux 源码结构

Redux API

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

createStore

上面咱们看到了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,那咱们就从这里开始讲起。异步

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
  }
相关文章
相关标签/搜索