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

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

下面我来对其进行解析~

INIT

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

export const ActionTypes = {
  INIT: '@@redux/INIT'
}

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

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()
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,

{
 dispatch,
 subscribe,
 getState
}

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

getState

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

function getState() {
   return currentState
}

subscribe

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

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

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

// 这个函数的作用就是,如果发现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)
    }
  }

在使用的时候就可以:

const unsubscribe = store.subscribe(() =>
  console.log(store.getState())
)

unsubscribe()

dispatch

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

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

返回:这个传入的object

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回它的初始状态

dispatch({ type: ActionTypes.INIT })

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏java达人

AbstractQueuedSynchronizer实现示例

AbstractQueuedSynchronizer提供了一个实现锁和同步器的框架,它处理很多细节点,比如先进先出等待队列,同时,我们可以自定义同步器的一些标准...

1988
来自专栏大内老A

在ASP.NET MVC中如何应用多个相同类型的ValidationAttribute?

ASP.NET MVC采用System.ComponentModel.DataAnnotations提供的元数据验证机制对Model实施验证,我们可以在Mode...

1995
来自专栏xingoo, 一个梦想做发明家的程序员

CIOCPServer的数据结构定义及内存池方案

为了避免频繁的申请释放内存,使用内存池来管理缓冲区对象和客户上下文对象使用的内存。 使用指针保存所有空闲的内存块,形成空闲列表。 申请内存时,这个指针不为NUL...

1909
来自专栏皮皮之路

【JDK1.8】JUC——ReentrantLock

在之前的几篇中,我们回顾了锁框架中比较重要的几个类,他们为实现同步提供了基础支持,从现在开始到后面,就开始利用之前的几个类来进行各种锁的具体实现。今天来一起看下...

973
来自专栏Java学习之路

从源码来看ReentrantLock和ReentrantReadWriteLock ReentrantLockReentrantReadWriteLock

上一篇花了点时间将同步器看了一下,心中对锁的概念更加明确了一点,知道我们所使用到的锁是怎么样获取同步状态的,我们也写了一个自定义同步组件Mutex,讲到了它其实...

3166
来自专栏LinXunFeng的专栏

iOS - Swift UICollectionView横向分页的问题UICollectionView横向分页的问题

1063
来自专栏码匠的流水账

聊聊kafka client chunkQueue 与 MaxLag值

前面一篇文章讨论了ConsumerFetcherManager的MaxLag与ConsumerOffsetChecker的lag值的区别。但是关于MaxLag的...

671
来自专栏闻道于事

JFinal框架使用

表单直接提交页面,不用ajax 后台; /** * 修改 */ public void edit() { Strin...

3675
来自专栏java、Spring、技术分享

AbstractQueuedSynchronizer源码解读

   AbstractQueuedSynchronizer(AQS),是 Java 并发包中,实现各种同步结构和部分其他组成单元(如线程池中的 Worker)的...

1233
来自专栏跟着阿笨一起玩NET

TreeView控件中实现拖拽的功能

701

扫码关注云+社区