createStore是一個高階函式,主要作用是完成store的初始化
createStore(reducer,preloadedState,enhancer)
export default function createStore(reducer, preloadedState, enhancer) {
// 只傳兩個引數並且第二個引數是函式的情況下,將其作為增強函式enhancer, 如createStore(reducer,applyMiddleware(middleWare))
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)
}
let currentReducer = reducer
let currentState = preloadedState // 通過閉包維持一份createStore的state tree,更新時,current指標將指向dispatch生成的new state tree, 通過getStateapi對外暴露最新的state tree
let currentListeners = [] // subscribe方法收集的訂閱
let nextListeners = currentListeners // 用於呼叫ensureCanMutateNextListeners 淺拷貝一份list,防止使用者在dispatching時呼叫subscribe/unsubscribe出現bug
let isDispatching = false // 是否正在更新state
function dispatch(action) {
try {
isDispatching = true
// 改變當前狀態
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
// 在dispatch改變當前狀態之後立即執行所有通過subscribe的函式,執行listener主要用於在更新狀態之後做些什麼事情,比如檢視的render操作,我們可以根據最新的狀態去渲染檢視
// 這種方式有一個缺點就是,不論你消費的資料有沒有變化,只要你使用subscribe訂閱了store,都會執行訂閱函式
// 也就是說,redux並不識別具體的訂閱者,而是統一廣播通知,但這一功能被react-redux實現了
const listeners = (currentListeners = nextListeners)
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
return action
}
dispatch({ type: ActionTypes.INIT }) // 執行createStore完成狀態初始化的時候,會在內部呼叫dispatch傳遞一個type為init的action, 並且返回一個store物件, 這也是唯一的一次非使用者生成的action排程
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}
createStore的幾個主要api
- dispatch
- subscribe/unsubscribe
- getState
dispatch
負責響應使用者的動作,派發action給reducer從而獲取最新的檢視狀態
dispatch在初始化的時候由redux自身呼叫一次init action,其他時候都是使用者由派發action呼叫
流程:
- dispatch將store的currentState指標指向reducer返回的new state
- 向使用者廣播通過subscribe註冊的所有訂閱
- 通過getState向使用者暴露currentState
function dispatch(action) {
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
}
subscribe
store.subscribe(listener)
訂閱redux 狀態變化,一旦狀態發生變化就執行所有的訂閱函式,同時返回一個取消訂閱的函式unsubscribe
function subscribe(listener) {
let isSubscribed = true
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
currentListeners = null
}
}
getState
createStore通過閉包維持一份state tree。
狀態更新時, currentState指標將指向dispatch生成的new state tree, 並通過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
}