import $$observable from 'symbol-observable'
import ActionTypes from './utils/actionTypes'
import isPlainObject from './utils/isPlainObject'
export default function createStore(reducer, preloadedState, enhancer) {
// 第一个参数为reducer,函数类型
// 第二个参数应为初始state,类型任意
// 第三个参数为enhancer,函数类型,即applyMiddleware返回的函数
if (
(typeof preloadedState === 'function' && typeof enhancer === 'function') ||
(typeof enhancer === 'function' && typeof arguments[3] === 'function')
) {
// 若preloadedState和enhancer均为函数,
// 或者参数个数多余三个且最后两个都是函数类型,
// 猜想使用了多个enhancer,抛出错误
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'
)
}
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
// 若preloadedState为函数类型,且enhancer为空,
// 猜想无初始state,第二个参数直接为enhancer
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
// 若enhancer存在但不是函数类型,则抛出错误,提示enhancer应该是一个函数
throw new Error('Expected the enhancer to be a function.')
}
// 若enhancer存在而且是函数类型,调用enhancer对递纳入参createStore
// 这里能够结合applyMiddleware理解,enhancer即为applyMiddleware的返回结果
return enhancer(createStore)(reducer, preloadedState)
}
if (typeof reducer !== 'function') {
// 判断reducer类型,非函数类型就报错
throw new Error('Expected the reducer to be a function.')
}
// 当前reducer
let currentReducer = reducer
// 当前state
let currentState = preloadedState
// 当前事件监听数组
let currentListeners = []
// 下一轮事件监听数组,此处与ensureCanMutateNextListeners相关联
let nextListeners = currentListeners
// 判断是否正在dispatch的标志
let isDispatching = false
function ensureCanMutateNextListeners() {/* ... */}
function getState() {/* ... */}
function subscribe(listener) {/* ... */}
function dispatch(action) {/* ... */}
function replaceReducer(nextReducer) {/* */}
function observable() {/* ... */}
// When a store is created, an "INIT" action is dispatched so that every
// reducer returns their initial state. This effectively populates
// the initial state tree.
dispatch({ type: ActionTypes.INIT })
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
复制代码
因为createStore
内部比较大,因此这里我将一些内部定义的函数拎出单独描述做用,对于其余的部分可参考中文注释内容。最后的英文注释也很好的描述了在建立store以后经过dispatch一次名字叫做INIT
的action来进行整个store的内部state初始化。总结一下非函数部份内部的功能就是如下几点内容:javascript
讲完了非函数部份内容,接下来一个一个分析一下在createStore
中定义的函数。java
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
复制代码
因为nextListeners
变量定义的时候是根据currentListeners
得到的数组引用(参考定义部分),因此为了避免影响当前事件监听数组,函数ensureCanMutateNextListeners
会在须要更改nextListeners
的时候先判断一下是不是当前事件监听数组的引用,如果,则会用slice
方法得到一个一样元素的不一样数组做为新的nextListeners
。redux
function getState() {
// 获取当前store中state,若是正在dispatch则报错
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
主要用于返回当前store中的state对象,须要注意的是若是当前store正在进行dispatch
操做,那么就不能获取state,而是抛出一个错误提示。api
function subscribe(listener) {
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-reference/store#subscribe(listener) 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-reference/store#subscribe(listener) for more details.'
)
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}
复制代码
这里的subscribe
函数主要用于添加用户事件的监听,会在dispatch
更新state后进行调用(详情在dispatch
部分说明),即将监听事件加入到nextListeners
。须要注意的是,该函数返回的是一个用于解除监听的unsubscribe
方法,这里利用的是闭包的经典用法,能够参考学习一下。数组
function dispatch(action) {
if (!isPlainObject(action)) {
// 判断是不是符合要求的plain object
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
if (typeof action.type === 'undefined') {
// 判断是否包含所需的type属性
throw new Error(
'Actions may not have an undefined "type" property. ' +
'Have you misspelled a constant?'
)
}
if (isDispatching) {
// 利用isDispatching判断当前是否正在进行dipatch操做
throw new Error('Reducers may not dispatch actions.')
}
// 更新标示,并利用当前reducer更新state
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
// 经过nextListeners得到最新的当前事件监听数组
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
// 遍历触发监听事件
const listener = listeners[i]
listener()
}
// 返回入参action
return action
}
复制代码
dispatch
函数能够说是用户接触最多的一个api了,功能很是强大,可是它的实现倒是很是好理解的。闭包
action
进行类型校验,判断是不是合法的plain object;action
是否包含标示更新类型的type
属性;dispatch
操做,若是是则抛出错误;action
做为入参传入currentReducer
获得最新的当前state;nextListeners
获取最新的事件监听数组,同时遍历触发每一个监听事件;action
备用。function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
// 判断nextReducer是不是符合要求的函数类型
throw new Error('Expected the nextReducer to be a function.')
}
// 更新当前reducer为最新的reducer
currentReducer = nextReducer
// 触发一次REPLACE类型的action用于使用最新的reducer更新当前store中state数据
dispatch({ type: ActionTypes.REPLACE })
}
复制代码
replaceReducer
函数接受一个新的reducer函数——nextReducer
做为入参,在内部替换掉currentReducer
,同时主动dispatch一次REPLACE
类型的私有action,用于应用最新的reducer方法更新state。从个人项目经从来说,这个replaceReducer
方法以及接下来的observable
方法,使用频率都不是过高,不知道具体使用场景会是什么样子以及其余人的状况如何。app
function observable() {
// 根据subscribe方法定义outerSubscribe方法,备用
const outerSubscribe = subscribe
// 返回一个包含subscribe方法的对象
return {
/** * The minimal observable subscription method. * @param {Object} observer Any object that can be used as an observer. * The observer object should have a `next` method. * @returns {subscription} An object with an `unsubscribe` method that can * be used to unsubscribe the observable from the store, and prevent further * emission of values from the observable. */
subscribe(observer) {
// 接受一个对象做为观察者observer
if (typeof observer !== 'object' || observer === null) {
// 校验observer类型
throw new TypeError('Expected the observer to be an object.')
}
// 定义一个监听state的方法
function observeState() {
if (observer.next) {
// 运行observer对象的next方法,以当前store的state做为入参
observer.next(getState())
}
}
// 执行一次observerState方法
observeState()
// 定义解除监听的方法,并做为一个对象的属性,返回该对象
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
// 获取当前对象的this指向
[$$observable]() {
return this
}
}
}
复制代码
坦白说,以前历来没有接触、使用过这个api,因此对于其做用知之甚少,暂时只能经过代码层面来解读其做用,后面能够进一步了解一下。async