Redux系列之👉 CreateStore

redux中最重要的莫过于我们的store对象了,store对象是通过一个函数调用生成的,对,就是本文的主题 👉 createStore函数。(看字面意思也能看出来 创造store)

store对象有三个最重要的属性:

  • dispatch
  • getState
  • subscribe

如果想探究这三个属性(方法)具体做了什么,我们不得不深入createStore函数。我们先从createStore的参数说起:

1
2
3
export default function createStore(reducer, preloadedState, enhancer) {
// ...
}
  • 第一个参数 reducer,对,就是你最熟悉的那个里面写了一大堆switch语句的纯函数。

  • 第二个参数preloadedState,表示state默认值,这个参数一般情况下不会传递,我们一般会在reducer函数中设置默认值。

  • 第三个参数enhancer,这个单词翻译过来👉 增强器,增强什么呢?其实是增强我们的dispatch函数的,也就是在dispatch中增加许多中间件。如果脑海中还是没有概念,可以看一下createStore是怎么使用: createStore(reducer, undefined, applayMiddleWare(middle1, middle2)),注意到了我们第三个参数了吗👉applayMiddleWare(middle1, middle2),是的applayMiddleWare充当了enhancer的角色,并且它最后会获取createStore权限,这是后话。

介绍完参数,我们进入函数体,最开始我们会看到这样一段代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  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)
  }

  if (typeof reducer !== 'function') {
    throw new Error('Expected the reducer to be a function.')
  }

我们会发现上面代码中,存在三个if条件语句,我们分别解释。

  1. 第一个if,正如我上面所说,当我们调用createStore时,通常都不会传递preloadedState,并且也不会显式地在该参数位置传递undefined,而是直接把enhancer函数直接放置第二个参数位置。这样造成的结果是preloadedState变成了enhancer,这绝对不行。所以我们需要把preloadedState赋值成undefined,把第二个位置传递的enhancer函数赋值给真正的enhancer变量。这就是我们第一个if在做的事情!

  2. 第二个if相对更好理解,如果enhancer函数存在,那么我把createStore权限交给enhancer。为什么要这么做?因为我们的enhancer增强器需要得到最新创建出来的store,然后增强dispatch函数,那还不如干脆就在enhancer里把活干了!

  3. 第三个if判断reducer类型,如果不是函数,随即抛出错误。

我们继续往下看....:

1
2
3
4
5
  let currentReducer = reducer
  let currentState = preloadedState
  let currentListeners = []
  let nextListeners = currentListeners
  let isDispatching = false

上面的代码也都很好理解,分别是reducerstatecurrentListenersnextListeners这两个变量最开始看可能很懵逼,其实它们两个变量是用来管理订阅列表的,还记得我们说过store拥有subscribe方法吗?就是这用到的。isDispatching表示是否正在dispatch中,我们的action必须要等到上一个dispatch结束才能继续发下一个action

所有的准备代码已经都弄懂了,我们终于可以看看dispatch、getState、subscribe的真面目了。我们先从最简单的getState看:

1
2
3
function getState() {
  return currentState;
}

是真的很简单,它返回我们的currentState。。。OK,那我们来介绍一下subscribe函数,上代码~:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function ensureCanMutateNextListeners() {
    if (nextListeners === nextListeners) {
      nextListeners = currentListeners.slice()
    }
}

function subscribe(listener) {
    if (typeof listener !== 'function') {
      throw new Error('Expected listener to be a function.')
    }

    let isSubscribed = true

    ensureCanMutateNextListeners()
    nextListeners.push(listener)

    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

上面的代码可以用一句话总结: subscribe函数接收订阅函数并将其push进nextListeners数组,然后返回一个unsubscribe函数用来解除订阅。其中有一个函数ensureCanMutateNextListeners的作用是为了防止修改nextListeners时,也把currentListeners不小心改掉,因为有时currentListenersnextListeners指向同一个数组。而unsubscribe函数里的逻辑就是找到那个订阅函数,然后从nextListeners数组里splice掉。subscribe的使用方式:

1
2
3
4
5
const unsubscribe = store.subscribe(() => {
  console.log('这可以监测到store的变化!')
})
// 解除订阅
unsubscribe();

重弹!dispatch函数来了:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function dispatch(action) {
    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?'
      )
    }
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

其实挺好理解的....dispatch主要做了的事情就是调用reducer函数,然后将返回值赋值给currentState,然后遍历我们的订阅列表,也就是nextListeners,然后依次调用订阅函数,最后把action对象返回....里面还会有根据isDispatching变量来控制dispatch的顺序,即无法并发,必须一个dispatch执行结束以后,再dispatch另一个action。

最后的最后crateStore还会dispatch一个初始化action:

dispatch({ type: ActionTypes.INIT } as A)

好了这就是createStore做的所有事情了,代码不多也好理解,难在就是想不出来....似乎还有一段很长的路要走呢!

updatedupdated2020-06-222020-06-22