redux 在初始化的时候都做了什么

521 阅读1分钟

最近稍微有些空闲时间于是就去看了一下redux的源码,研究了一下createstore的过程中程序做了什么

createStore可以有三个参数

reducer

处理数据的纯函数,每一个reducer都会返回一个状态

preloadedState(可选参数)

整个store在初始化前的初始值(state树的根),preloadedState和我们reducer中设置的默认state不同 ,是在执行reducer函数前就已经存在的

enhancer (可选参数)

增强器或者中间件,诸如我们常用的redux-thunk和redux-saga 都是在这一块对redux进行增强的

image.png

好了接下来咱来理一理createStore对这三个入参做了啥吧

在对入参进行一系列类型校验和数量校验后

大致上有两个情况

参数中不含有enhancer函数

程序内部会先初始化好几个变量

  let currentReducer = reducer //当前初始化时传入的reducer纯函数
  let currentState = preloadedState as S //初始化前的默认状态设置为状态树的当前状态
  let currentListeners: (() => void)[] | null = [] //订阅者们
  let nextListeners = currentListeners //下一次的订阅者
  let isDispatching = false //是否正在处理dispatching,确保只有一个dispatching正在执行

初始化好store的几个内部变量后,程序会向store中dispath一个自带的action ActionTypes.INIT 代表store已经初始化完毕

dispatch({ type: ActionTypes.INIT } as A)

随后返回向外暴露的一些对象和方法的合集

    const store = ({
        dispatch: dispatch as Dispatch<A>,
        subscribe,
        getState,
        replaceReducer,
        [$$observable]: observable
    } as unknown) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
    return store

参数中含有enhancer函数

createStore内部会判断传入的enhancer是不是一个函数,如果是一个函数的话则把createStore传入到enhancer中作为一个形参,并执行enhancer,然后enhancer会返回一个增强过的StoreEnhancerStoreCreator (一个增强过的createStore函数)并把当前的reducer和preloadedState传入并执行函数 返回一个新的store

    if (typeof enhancer !== 'undefined') {
        if (typeof enhancer !== 'function') {
          throw new Error(
            `Expected the enhancer to be a function. Instead, received: '${kindOf(
              enhancer
            )}'`
          )
        }

        return enhancer(createStore)(
          reducer,
          preloadedState as PreloadedState<S>
        ) as Store<ExtendState<S, StateExt>, A, StateExt, Ext> & Ext
      }

store对外暴露的方法

dispatch

dispatch(Action) 是redux中修改某个值的唯一方式

dispath 函数做的事情其实特别简单,他负责对aciton进行校验,符合action的数据格式之后,把 isDispatching的值变成true,防止多个dispatching存在,然后再调用当前的currentReducer,把当前的state和action作为参数 ,然后拿到返回的新的state 替换掉之前的currentState对象。

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action)
    } finally {
      isDispatching = false
    }

到这里state已经修改好了

是不是觉得缺了什么?

对,得告诉所有的订阅者(订阅了store中数据变化事件的)listener 我进行了一次dispatch了!!!

所以该函数最后会对listeners 进行遍历,执行所有的listener。

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

最后会返回一个action。

注意:并不是所有情况下dispath函数都会返回action ,是因为在某些增强中间件中,把这一块的返回给改了 ,比如说thunk dispath是可以返回一个promise对象的!!!

getState

这个真的很简单,调用后会把当前的currentState返回

subscribe

订阅store的状态变化

subscribe的参数是一个函数 () => void

调用方法时会在方法内部初始化一个人变量

let isSubscribed = true

然后对当前的currentListeners进行一个深拷贝 到 nextListeners中

拷贝完成之后把传入的函数push 到 nextListeners中

最后会返回一个unsubscribe方法

订阅后每次store发生变化都会调用nextListeners中所有的函数

关于unsubscribe所做的事情

在解除订阅的时候修改 isSubscribed 的值为false

对当前的currentListeners进行一个深拷贝 到 nextListeners中

最后从 nextListeners 中删除掉相关方法的内存地址,再把currentListeners 变为null

这样就完成了解除订阅的流程了

replaceReducer

replaceReducer的作用是把一个新的reducer对象替换到现有的store当中

然后返回一个新的store对象,这一块在对store中进行全面的数据重制的时候还是挺好用的

在reducer替换成功后会发送一个内置的action ActionTypes.REPLACE

具体的实现代码是这样的

function replaceReducer<NewState, NewActions extends A>(
    nextReducer: Reducer<NewState, NewActions>
  ): Store<ExtendState<NewState, StateExt>, NewActions, StateExt, Ext> & Ext {
    if (typeof nextReducer !== 'function') {
      throw new Error(
        `Expected the nextReducer to be a function. Instead, received: '${kindOf(
          nextReducer
        )}`
      )
    }
    ;((currentReducer as unknown) as Reducer<
      NewState,
      NewActions
    >) = nextReducer

    
    dispatch({ type: ActionTypes.REPLACE } as A)
    
    return (store as unknown) as Store<
      ExtendState<NewState, StateExt>,
      NewActions,
      StateExt,
      Ext
    > &
      Ext
  }

[$$observable]

观察者模式相关的这一块之后再细讲