最近稍微有些空闲时间于是就去看了一下redux的源码,研究了一下createstore的过程中程序做了什么
createStore可以有三个参数
reducer
处理数据的纯函数,每一个reducer都会返回一个状态
preloadedState(可选参数)
整个store在初始化前的初始值(state树的根),preloadedState和我们reducer中设置的默认state不同 ,是在执行reducer函数前就已经存在的
enhancer (可选参数)
增强器或者中间件,诸如我们常用的redux-thunk和redux-saga 都是在这一块对redux进行增强的
好了接下来咱来理一理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]
观察者模式相关的这一块之后再细讲