使用redux都快3年了,到如今也沒認真去了解一下源碼罪過啊,因此須要對它進行一些分析和學習,一方面能更好的去使用它,另外一方面也學習一下該框架的設計思路,首先咱們看到 redux/src/index.js 文件git
export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose,
__DO_NOT_USE__ActionTypes
}
複製代碼
因此主要部分也就是上面幾個函數,咱們下面一點點去分析每個功能點github
其實該文件有着大量的註釋了,你們能夠先簡單的看看代碼中的註釋瞭解一遍。 其實createStore就是返回了一個對象,這個對象只有幾個方法而已,而咱們經常使用的就是dispatch,subscribe,getState這三個了redux
* Creates a Redux store that holds the state tree.
* The only way to change the data in the store is to call `dispatch()` on it.
複製代碼
該函數的做用呢就是創建一個store(廢話嘛),那麼什麼是store呢?個人理解 就是一個倉庫,存着整個程序的狀態,且只能有一個,就是用這一個store搞定項目中的所有狀態,固然不論多大的項目,通通只有這一個,弄兩個確定很差使,而且只有一個路子去修改裏面的數據,那麼就是調用dispatch()api
function createStore(reducer, preloadedState, enhancer)
複製代碼
能夠看到函數體主要三個參數,簡單說下數組
(preState,action) => newState
就是說根據action和以前的狀態,返回一個新的狀態(這裏的新是新構建,而不是修改過,這點切記)if (typeof preloadedState === 'function' && typeof enhancer === 'undefined') {
enhancer = preloadedState
preloadedState = undefined
}
複製代碼
也容易理解,在只有兩個參數的狀況,而且第二個爲funcion的時候,那麼第二個參數就是enhancer了,交互一下參數位置bash
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
複製代碼
對enchancer類型判斷,能夠看到enhancer就是將store傳入,在內部處理以後再將store返回來,繼續傳入reducer和初始狀態進行構建app
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}
複製代碼
創建一些變量保存reducer,state,以及訂閱器保存在nextListeners中,ensureCanMutateNextListeners至關於每次對當前的訂閱器進行備份,由於每次訂閱一個listener的時候都是對nextListeners數組進行添加框架
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)
}
}
複製代碼
訂閱器,註冊監聽函數,每個listener都是一個func,而且返回了一個取消註冊監聽的函數unScribe,用於刪除listener,其實就是將一個個的函數添加到數組中,以後每次在store發生變化的時候(其實也就是調用dispatch的時候)就會觸發它~async
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
}
複製代碼
上面呢就是這裏比較重要的dispatch函數了,其實很是簡單,主要就是它:函數
currentState = currentReducer(currentState, action)
複製代碼
將當前的所有狀態和action傳入reducer,獲得新的state,這樣就完成了state的狀態更新了,以後再去遍歷所有的listeners,從而在各個listeners的內部去更新view,完成整個流程(返回值其實仍是這個action對象),其實以上內容和三個函數應該是redux的核心內容了,下面用一種簡單的總結來表達一下store(借鑑的阮一峯的)
const createStore = (reducer) => {
let state;
let listeners = [];
const getState = () => state;
const dispatch = (action) => {
state = reducer(state, action);
listeners.forEach(listener => listener());
};
const subscribe = (listener) => {
listeners.push(listener);
return () => {
listeners = listeners.filter(l => l !== listener);
}
};
dispatch({});
return { getState, dispatch, subscribe };
};
複製代碼
而該文件還有兩個函數分別是
function replaceReducer(nextReducer)
function observable()
複製代碼
第一個很明顯替換整個reducer用,在一些熱加載場景應該會用到 而第二個暫時還不太理解做者意圖,用觀察者替換訂閱發佈嗎?暫時先不去想 以上就是整個createStore的源碼分析~
更多內容與討論能夠參考個人github.com/jinjiaxing/…