函数作用
创建一个store对象并返回。
函数定义
createStore函数内部定义很多函数,比如getState, dispacth。先忽略这些内部函数的函数体,那么createStore就像下面这样。
function createStore(reducer,preloadedState,enhancer)}{
let currentReducer = reducer;
let currentState = preloadedState;
let currentListeners=[];
let nextListeners = currentListeners;
let isDispatching = false;
function ensureCanMutateNextListeners() {}
function getState(){}
function subscribe(){}
function dispatch(){}
function replaceReducer(){}
function observable(){}
const store = {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
return store;
}
利用闭包的原理使得我们可以通过store.getState()获取当前的state,通过store.dispatch(Action)更改state。
接下来看看各个内部函数的实现。
getState
function getState(){
if (isDispatching) {
throw new Error(
'You may not call store.getState() while the reducer is executing. ' +
'The reducer has already received the state as an argument. ' +
'Pass it down from the top reducer instead of reading it from the store.'
)
}
return currentState;
}
getState函数特别简单,就是直接返回currentState,只不过会判断一下isDispatching是否为true。
2.dispatch
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?'
)
}
if (isDispatching) {
throw new Error('Reducers may not dispatch actions.')
}
try {
isDispatching = true
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是否是普通的对象。那什么样的对象才是普通的呢?看看isPlainObject的实现。
function isPlainObject(obj){
if (typeof obj !== 'object' || obj === null) return false
let proto = obj
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(obj) === proto
}
可以看出,该函数是通过判断obj的原型对象是否与while循环得到的原型对象是否相等来确定obj是否为普通对象。意思就是action只能是通过对象字面量形式{}或new Object()创建的。但是在我看来这个函数完全可以写成这样。
function isPlainObject(obj){
if (typeof obj !== 'object' || obj === null) return false;
return Object.getPrototypeOf(obj) === Object.prototype;
}
然后会检查action上是否存在type属性。接着执行reducer并将返回结果赋值给currentState。
最后遍历listeners触发由store.subscribe注册的监听器。
subscribe
function subscribe(listener: () => void) {
if (typeof listener !== 'function') {
throw new Error('Expected the listener to be a function.')
}
if (isDispatching) {
throw new Error(
'You may not call store.subscribe() while the reducer is executing. ' +
'If you would like to be notified after the store has been updated, subscribe from a ' +
'component and invoke store.getState() in the callback to access the latest state. ' +
'See https://redux.js.org/api/store#subscribelistener for more details.'
)
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
if (isDispatching) {
throw new Error(
'You may not unsubscribe from a store listener while the reducer is executing. ' +
'See https://redux.js.org/api/store#subscribelistener for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
currentListeners = null
}
}
将监听器推入nextListeners数组中,返回一个取消订阅函数。调用取消订阅函数会将监听器从nextListeners中删除并修改isSubscribed为false防止多次调用。
现在再来看看createStore的第三个函数enhancer。
function createStore=(reducer,preloadedState,enhancer){
...
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer,preloadedState);
}
//定义各个内部函数,创建store对象并返回
...
}
当enhancer存在并且是函数的时候,会调用enhancer,接着调用enhancer的执行结果,由此可以看出enhancer是一个高阶函数,接收storeCreator并返回另一个storeCreator,以此增强store功能。如果我们想自定义一个enhancer,那么我们的enhancer应该是一个形如下面的函数
function myEnhancer(storeCreator){
return (reducer,preloadedState)=>{
const store = storeCreator(reducer,preloadedState);
//增强store
...
return store;
}
}
applyMiddleware是官方提供的enhancerCreator,它增强的是store.dispatch。
如果想使用多个enhancer请使用compose函数,像这样createStore(reducer,defaultState,compose(enhancer1,enhancer2)),不可以createStore(reducer,defaultState,enhancer1,enhancer2),原因看这里。
function createStore=(reducer,preloadedState,enhancer){
if (
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
) {
throw new Error(
'It looks like you are passing several store enhancers to ' +
'createStore(). This is not supported. Instead, compose them ' +
'together to a single function.'
)
}
...
}
欢迎指出错误😀。