React-Redux 源码解析 一(createStore)

createStore

一般而言,我查看一个库的源代码,首先回查看对应方法的参数,其次是对应的return ,然后再看代码的具体实现。

通过查看源码,发现createStore 方法返回了一个对象, 该对象共暴露出了五个方法,四个常用的方法:

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
复制代码

查看源码的开始部分,我们发现createStore可以传入两个三个参数:

export default function createStore(reducer, preloadedState, enhancer) 
复制代码

其中第一个参数reducer 是必须要传递的而且必须是一个函数,不然Redux回报一场

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

如果传递了第二个参数preloadedState,而且第二个参数不是一个function , 则将preloadedState 保存在内部变量currentState中, 也就是我们给State 的默认状态

如果preloadedState 是一个function , 则将preloadedState 赋值给enhancer

  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.')
    }
    // 运行enhancer, 一般enhancer 就是一组中间件
    return enhancer(createStore)(reducer, preloadedState)
  }

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

该方法中保存了三个重要的变量:

let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
复制代码
  1. currentReducer 保存了所有的Reducer
  2. currentState 将状态数据都保存在这里,也是Redux 操作数据的唯一对象
  3. currentListeners 会保存对Redux State 订阅的监听者

我们已经知道了Redux能控制的如上三个主要内部变量了, 接下拉我们会 根据createStore 暴露出来的五个方法,来学习怎么去操作这三个变量

  return {
    dispatch,
    subscribe,
    getState,
    replaceReducer,
    [$$observable]: observable
  }
复制代码

dispatch(去掉验证代码)

  function dispatch(action) {
      try {
      isDispatching = true
      // 调用Reduce 对action 进行处理,每次传入原始的state.返回更新后的states
      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 参数来告诉需要做的操作对象,action 只能是一个Object, 而且必须包含type 字段

    if (!isPlainObject(action)) {
      throw new Error(
        'Actions must be plain objects. ' +
        'Use custom middleware for async actions.'
      )
    }

    if (typeof action.type === 'undefined') { // 必须包含**Type**
      throw new Error(
        'Actions may not have an undefined "type" property. ' +
        'Have you misspelled a constant?'
      )
    }
复制代码

我们会调用内部变量currentReducer 去处理发起的对应的action

currentState = currentReducer(currentState, action)
复制代码

我们会发现currentReducer 其实是一个function, 而且需要两个参数: currentState , action.

currentReducer 返回的值赋值给currentState, 由createStore 传入参数的分析得知,preloadedState 只能是要给Object, 所以currentReducer function 返回的是要给Object.

从这一行代码我们可以总结得到:

reducer 其实就是一个函数,根据action 对 currentState 进行处理,并且返回新的currentState 的函数

 const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener()
    }
复制代码

由上面一段代码我们可以得知,在更新state , 需要去遍历执行所有的监听者(listener),让监听者得知state变更的信息

subscribe(订阅)

subscribe顾名思义就是消息订阅的意思

  function subscribe(listener) {
    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)
    }
  }
复制代码

很简单的一段代码, 传入的参数listener 就是一个订阅者方法,

 nextListeners.push(listener)
复制代码

将listener 保存在内部变量数组中。返回一个unsubscribe方法, 用来取消订阅

nextListeners.splice(index, 1) // 只要从数组中删除listener 就是取消订阅了
复制代码

getState(获取状态)

  function getState() {
    return currentState
  }
复制代码

非常简单,就是返回内部变量currentState

replaceReducer(替换reducer)

 function replaceReducer(nextReducer) {
    currentReducer = nextReducer
    dispatch({ type: ActionTypes.REPLACE })
  }

复制代码

就是替换当前的reducer.

总结

  1. 首先我们需要调用createStore 方法创建一个store
 let store = createStore(reducer, preloadedState)
复制代码

reducer 是一个function, 而且必须要 传递两个参数,第一个是state, 第二个是一个action

  1. 利用相关事件触发store.dispatch(action)去变更状态

这个action 必须要有type 属性

  1. 订阅状态变更store.subscribe(listener)
  2. 在listener中去获取最新state(store.getState()),然后做去相应的处理

可以在Redux examples 下载代码运行查看效果.
作者:bluebrid
链接:https://juejin.im/post/5b822fa951882542ec1995d3
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

猜你喜欢

转载自blog.csdn.net/sinat_17775997/article/details/83177551