浅析redux源码之createStore

291 阅读2分钟

函数作用

创建一个store对象并返回。

函数定义

createStore函数内部定义很多函数,比如getState, dispacth。先忽略这些内部函数的函数体,那么createStore就像下面这样。

function createStore(reducer,preloadedState,enhancer)}{
    let currentReducer = reducer;
    let currentState = preloadedState;
    let currentListeners=[];
    let nextListeners = currentListeners;
    let isDispatching = false;
    function ensureCanMutateNextListeners() {}
    function getState(){}
    function subscribe(){}
    function dispatch(){}
    function replaceReducer(){}
    function observable(){}
    const store = {
        dispatch,
        subscribe,
        getState,
        replaceReducer,
        [$$observable]: observable
    }
    return store;
}

利用闭包的原理使得我们可以通过store.getState()获取当前的state,通过store.dispatch(Action)更改state。

接下来看看各个内部函数的实现。

  1. getState
function getState(){
    if (isDispatching) {
      throw new Error(
        'You may not call store.getState() while the reducer is executing. ' +
          'The reducer has already received the state as an argument. ' +
          'Pass it down from the top reducer instead of reading it from the store.'
      )
    }
    return currentState;
  }

getState函数特别简单,就是直接返回currentState,只不过会判断一下isDispatching是否为true。

2.dispatch

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
  }

首先会判断action是否是普通的对象。那什么样的对象才是普通的呢?看看isPlainObject的实现。

function isPlainObject(obj){
  if (typeof obj !== 'object' || obj === null) return false

  let proto = obj
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto)
  }

  return Object.getPrototypeOf(obj) === proto
}

可以看出,该函数是通过判断obj的原型对象是否与while循环得到的原型对象是否相等来确定obj是否为普通对象。意思就是action只能是通过对象字面量形式{}new Object()创建的。但是在我看来这个函数完全可以写成这样。

function isPlainObject(obj){
  if (typeof obj !== 'object' || obj === null) return false;
  return Object.getPrototypeOf(obj) === Object.prototype;
}

然后会检查action上是否存在type属性。接着执行reducer并将返回结果赋值给currentState

最后遍历listeners触发由store.subscribe注册的监听器。

  1. subscribe
function subscribe(listener: () => void) {
    if (typeof listener !== 'function') {
      throw new Error('Expected the listener to be a function.')
    }
    if (isDispatching) {
      throw new Error(
        'You may not call store.subscribe() while the reducer is executing. ' +
          'If you would like to be notified after the store has been updated, subscribe from a ' +
          'component and invoke store.getState() in the callback to access the latest state. ' +
          'See https://redux.js.org/api/store#subscribelistener for more details.'
      )
    }
    let isSubscribed = true
    ensureCanMutateNextListeners()
    nextListeners.push(listener)
    return function unsubscribe() {
      if (!isSubscribed) {
        return
      }
      if (isDispatching) {
        throw new Error(
          'You may not unsubscribe from a store listener while the reducer is executing. ' +
            'See https://redux.js.org/api/store#subscribelistener for more details.'
        )
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
      currentListeners = null
    }
  }

将监听器推入nextListeners数组中,返回一个取消订阅函数。调用取消订阅函数会将监听器从nextListeners中删除并修改isSubscribedfalse防止多次调用。

现在再来看看createStore的第三个函数enhancer。

function createStore=(reducer,preloadedState,enhancer){
  ...
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    return enhancer(createStore)(reducer,preloadedState);
  }
  //定义各个内部函数,创建store对象并返回
  ...
}

enhancer存在并且是函数的时候,会调用enhancer,接着调用enhancer的执行结果,由此可以看出enhancer是一个高阶函数,接收storeCreator并返回另一个storeCreator,以此增强store功能。如果我们想自定义一个enhancer,那么我们的enhancer应该是一个形如下面的函数

function myEnhancer(storeCreator){
    return (reducer,preloadedState)=>{
        const store = storeCreator(reducer,preloadedState);
        //增强store
        ...
        return store;
    }
}

applyMiddleware是官方提供的enhancerCreator,它增强的是store.dispatch

如果想使用多个enhancer请使用compose函数,像这样createStore(reducer,defaultState,compose(enhancer1,enhancer2)),不可以createStore(reducer,defaultState,enhancer1,enhancer2),原因看这里。

function createStore=(reducer,preloadedState,enhancer){
    if (
        (typeof preloadedState === 'function' && typeof enhancer === 'function') ||
        (typeof enhancer === 'function' && typeof arguments[3] === 'function')
      ) {
        throw new Error(
          'It looks like you are passing several store enhancers to ' +
            'createStore(). This is not supported. Instead, compose them ' +
            'together to a single function.'
        )
      }
      ...
}

欢迎指出错误😀。

源码地址:github.com/reduxjs/red…