Redux 源码解读之 createStore


combineReducers 源码地址:node_modules/redux/src/createStore.js。
createStore 的核心功能是创建一个 store,返回所有 redux 需要用到的方法。

一、参数类型校验与变量初始化

 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.'
    )
  }
  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.')
  }

首先对 createStore 函数的三个参数进行类型校验。

  1. 第一个参数类型整合的 reducer 必须是一个 function;
  2. 第二个参数 preloadedState(初始化state) 与第三个参数 enhancer (增强 redux 功能)类型不能同时为 function。只需要将第二个参数设置为 function。会将该参数值赋值给第三个参数,而第二个参数置为 undefined。
  3. 当第二个参数 preloadedState 类型为 function 时。return 执行第三个参数 enhancer ,需要注意的是,第三个参数为高阶函数,即函数(createStore 作为该函数参数)内必须返回一个函数。reducer 和 preloadedState 将作为返回函数的参数。

其次定义初始化变量。

 let currentReducer = reducer;//初始化当前 reducer
 let currentState = preloadedState;//初始化当前 state
 let currentListeners = [];//初始化当前监听函数数组
 let nextListeners = currentListeners;//初始化下一个监听函数数组
 let isDispatching = false;//初始化 dispatch 状态 

二、ensureCanMutateNextListeners 函数

 function ensureCanMutateNextListeners() {
    if (nextListeners === currentListeners) {
      nextListeners = currentListeners.slice()
    }
  }
  1. 下一个事件监听 list 是当前事件监听 list 的浅复制,其目的是为了在 dispatching 状态的时候,短暂的保留当前事件监听 list。这是为了避免在 dispatching 期间调用订阅/取消订阅 产生bug。
  2. 当前事件监听 list 等于下一个监听 list 时,修改下一个监听 list 。
  3. 在执行 subscribe 订阅事件的时候调用。

三、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
  }
  1. 当处在 dispatching 状态的时候,不能调用 getState 方法。
  2. 否则,直接返回 currentState (当前 state)。

四、subscribe 函数

  function subscribe(listener) {
    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-reference/store#subscribe(listener) 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-reference/store#subscribe(listener) for more details.'
        )
      }
      isSubscribed = false
      ensureCanMutateNextListeners()
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }
  1. 参数类型必须为 function。
  2. 不可在 dispatching 状态下执行。
  3. 执行 ensureCanMutateNextListeners()。
  4. 将参数(事件监听) push 到 nextListeners (下一个事件监听 list )中。
  5. 作为高阶函数,返回取消事件监听函数。
  6. 在取消事件监听函数中,处在 dispatching 状态下不可该执行。将该事件从 nextListeners 中删除。

五、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
  }
  1. actions 必须是一个简单的对象,如果是异步 action,需要使用中间件 middleware。
  2. 不可在 dispatching 状态下执行。
  3. action 必须有一个 type 属性。
  4. 不可在 dispatching 状态下执行。
  5. 将 isDispatching 状态设置为 true。将当前 state 和传过来的 action 作为参数调用 currentReducer(当前 reducer)。将结果赋值给 currentState(当前 state)。重置 isDispatching 为false。这种形式决定了 dispatch 必须为同步(异步变更需要中间件来完成)。
  6. 更改了当前 state 之后,执行每一个订阅事件。
  7. 返回 action。

六、replaceReducer 函数

 function replaceReducer(nextReducer) {
    if (typeof nextReducer !== 'function') {
      throw new Error('Expected the nextReducer to be a function.')
    }
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }
  1. 参数类型必须为 function 。
  2. 将参数赋值给 currentReducer (当前 reducer)。
  3. 调用 type 为 REPLACE 的 dispatch,初始化 state 树中的所有 state 节点。
    replaceReducer 的使用场景:代码分割、动态加载 reducer、实现 reloading 机制。

七、observable 函数

 function observable() {
    const outerSubscribe = subscribe
    return {
      subscribe(observer) {
        if (typeof observer !== 'object' || observer === null) {
          throw new TypeError('Expected the observer to be an object.')
        }
        function observeState() {
          if (observer.next) {
            observer.next(getState())
          }
        }
        observeState()
        const unsubscribe = outerSubscribe(observeState)
        return { unsubscribe }
      },

      [$$observable]() {
        return this
      }
    }
  }
  1. 观察者必须是一个对象,并且提供 next 方法 。
  2. 将当前 state 作为参数,执行 next 方法。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值