Redux 源码解读之 createStore
combineReducers 源码地址:node_modules/redux/src/createStore.js。
createStore 的核心功能是创建一个 store,返回所有 redux 需要用到的方法。
一、参数类型校验与变量初始化
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.'
)
}
if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
if (typeof reducer !== 'function') {
throw new Error('Expected the reducer to be a function.')
}
首先对 createStore 函数的三个参数进行类型校验。
- 第一个参数类型整合的 reducer 必须是一个 function;
- 第二个参数 preloadedState(初始化state) 与第三个参数 enhancer (增强 redux 功能)类型不能同时为 function。只需要将第二个参数设置为 function。会将该参数值赋值给第三个参数,而第二个参数置为 undefined。
- 当第二个参数 preloadedState 类型为 function 时。return 执行第三个参数 enhancer ,需要注意的是,第三个参数为高阶函数,即函数(createStore 作为该函数参数)内必须返回一个函数。reducer 和 preloadedState 将作为返回函数的参数。
其次定义初始化变量。
let currentReducer = reducer;//初始化当前 reducer
let currentState = preloadedState;//初始化当前 state
let currentListeners = [];//初始化当前监听函数数组
let nextListeners = currentListeners;//初始化下一个监听函数数组
let isDispatching = false;//初始化 dispatch 状态
二、ensureCanMutateNextListeners 函数
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
- 下一个事件监听 list 是当前事件监听 list 的浅复制,其目的是为了在 dispatching 状态的时候,短暂的保留当前事件监听 list。这是为了避免在 dispatching 期间调用订阅/取消订阅 产生bug。
- 当前事件监听 list 等于下一个监听 list 时,修改下一个监听 list 。
- 在执行 subscribe 订阅事件的时候调用。
三、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
}
- 当处在 dispatching 状态的时候,不能调用 getState 方法。
- 否则,直接返回 currentState (当前 state)。
四、subscribe 函数
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)
}
}
- 参数类型必须为 function。
- 不可在 dispatching 状态下执行。
- 执行 ensureCanMutateNextListeners()。
- 将参数(事件监听) push 到 nextListeners (下一个事件监听 list )中。
- 作为高阶函数,返回取消事件监听函数。
- 在取消事件监听函数中,处在 dispatching 状态下不可该执行。将该事件从 nextListeners 中删除。
五、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
}
- actions 必须是一个简单的对象,如果是异步 action,需要使用中间件 middleware。
- 不可在 dispatching 状态下执行。
- action 必须有一个 type 属性。
- 不可在 dispatching 状态下执行。
- 将 isDispatching 状态设置为 true。将当前 state 和传过来的 action 作为参数调用 currentReducer(当前 reducer)。将结果赋值给 currentState(当前 state)。重置 isDispatching 为false。这种形式决定了 dispatch 必须为同步(异步变更需要中间件来完成)。
- 更改了当前 state 之后,执行每一个订阅事件。
- 返回 action。
六、replaceReducer 函数
function replaceReducer(nextReducer) {
if (typeof nextReducer !== 'function') {
throw new Error('Expected the nextReducer to be a function.')
}
currentReducer = nextReducer
dispatch({ type: ActionTypes.REPLACE })
}
- 参数类型必须为 function 。
- 将参数赋值给 currentReducer (当前 reducer)。
- 调用 type 为 REPLACE 的 dispatch,初始化 state 树中的所有 state 节点。
replaceReducer 的使用场景:代码分割、动态加载 reducer、实现 reloading 机制。
七、observable 函数
function observable() {
const outerSubscribe = subscribe
return {
subscribe(observer) {
if (typeof observer !== 'object' || observer === null) {
throw new TypeError('Expected the observer to be an object.')
}
function observeState() {
if (observer.next) {
observer.next(getState())
}
}
observeState()
const unsubscribe = outerSubscribe(observeState)
return { unsubscribe }
},
[$$observable]() {
return this
}
}
}
- 观察者必须是一个对象,并且提供 next 方法 。
- 将当前 state 作为参数,执行 next 方法。