Redux源码解析系列 (三)-- createStore

2019-12-03 15:12:26 浏览数 (1)

本文作者:IMWeb 黄qiong 原文出处:IMWeb社区 未经同意,禁止转载

createStore源码地址为:https://github.com/reactjs/redux/blob/master/src/createStore.js

下面我来对其进行解析~

INIT

这个方法是redux保留用的,用来初始化reducer的状态

代码语言:javascript复制
export const ActionTypes = {
  INIT: '@@redux/INIT'
}

前面说 createStore的作用就是:创建一个store来管理app的状态,唯一改变状态的方式就是dispatch一个action,最终返回一个object。

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

不过replaceReducer,跟$$observable:都不常用~ ,所以这里只对前三的接口做解析。

createStore

在一个app里,只能有一个store,如果你想指明不同的state对应不同的action,可以用combineReducers去合并不同的reducer。

参数:

  • reducer(function):就是通过传入当前State,还有action,计算出下一个state,返回回来。
  • preloadedState(any):initial state
  • enhancer(function):增强store的功能,让它拥有第三方的功能,比如middleware.Redux里面唯一的enhancer就是applyMiddleware()
代码语言:javascript复制
export default function createStore(reducer, preloadedState, enhancer) {
// 第一段说的就是当第二个参数没有传preloadedState,而直接传function的话,就会直接把这个function当成enhancer
  if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
    enhancer = preloadedState
    preloadedState = undefined
  }
  // 当第三个参数传了但是不是function也会报错
  if (typeof enhancer !== 'undefined') {
    if (typeof enhancer !== 'function') {
      throw new Error('Expected the enhancer to be a function.')
    }
    //关键的一个就在于这里了,在前一篇讲applyMiddleware的时候介绍了这么做的意义,
    //实际就是把createStore这件事在applyMiddleware里面做,转移了锅。
    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 = []
  let nextListeners = currentListeners
  let isDispatching = false
}

上面是第一个part,在校验完参数的正确之后,终于可以干点正事儿了。 createStore最终会返回一个Object,

代码语言:javascript复制
{
 dispatch,
 subscribe,
 getState
}

接下来看看里面都做了什么:

getState

getState作用就是将当前state的状态返回回来,没啥好说的~

代码语言:javascript复制
function getState() {
   return currentState
}

subscribe

作用:添加监听函数listener,它会在每次dispatch action的时候调用。

参数:listener(function): 在每一次dispatch action的时候都会调用的函数

返回:返回一个移除listener的函数

代码语言:javascript复制
// 这个函数的作用就是,如果发现nextListeners,nextListeners指向同一个堆栈的话,就浅复制一份,这样改nextListeners就不会改到currentListeners
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里
    nextListeners.push(listener)

    return function unsubscribe() {
    // 如果已经移除了就直接返回
      if (!isSubscribed) {
        return
      }

      isSubscribed = false

      ensureCanMutateNextListeners()
      // 没有移除的话,先找到位置,通过splice移除
      const index = nextListeners.indexOf(listener)
      nextListeners.splice(index, 1)
    }
  }

在使用的时候就可以:

代码语言:javascript复制
const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

unsubscribe()

dispatch

dispatch 作为一个重点函数~ 其实它的作用就是触发状态的改变。

参数:action(object),它是一个描述发生了什么的对象,其中type是必须的属性。

返回:这个传入的object

代码语言:javascript复制
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?'
      )
    }
    // 防止多次dispatch请求同时改状态,一定是前面的dispatch结束之后,才dispatch下一个
    if (isDispatching) {
      throw new Error('Reducers may not dispatch actions.')
    }

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }
    // 在dispatch的时候,又将nextListeners 赋值回currentListeners,
    const listeners = currentListeners = nextListeners
    for (let i = 0; i < listeners.length; i  ) {
      const listener = listeners[i]
      listener()
    }

    return action
  }

在上面一系列完成之后,需要初始化appState的状态。当INIT action被dispatched 的时候,每个reducer都会return回它的初始状态

代码语言:javascript复制
dispatch({ type: ActionTypes.INIT })

参考资料: https://github.com/reactjs/redux/blob/master/src/createStore.js

0 人点赞