export {
createStore,
combineReducers,
bindActionCreators,
applyMiddleware,
compose
}複製代碼
今天咱們首先先分析createStore.js(ps:若是你看到index.js的話,必定一眼就看到createStore.js)
一、export const ActionTypes = {
INIT: '@@redux/INIT'
}複製代碼
二、export default function createStore(reducer, preloadedState, enhancer) {
return {
dispatch,
subscribe,
getState,
replaceReducer,
[$$observable]: observable
}
}複製代碼
很驚奇
ActionTypes定義、暴露這個幹嗎?何用?其實用處很大,
初始化的state狀態倉庫就是dispatch(ActionTypes),以前很驚奇好奇,redux怎麼初始化狀態(ps:用慣了vuex),
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.')
}複製代碼
let currentReducer = reducer
let currentState = preloadedState
let currentListeners = []
let nextListeners = currentListeners
let isDispatching = false複製代碼
function ensureCanMutateNextListeners() {
if (nextListeners === currentListeners) {
nextListeners = currentListeners.slice()
}
}複製代碼
1. 獲取當前狀態的 getStatevue
function getState() {
return currentState
}複製代碼
2.訂閱函數,參數是listener回掉函數。將listener函數放進nextListener數組內
function subscribe(listener) {
if (typeof listener !== 'function') {
throw new Error('Expected listener to be a function.')
}
let isSubscribed = true
ensureCanMutateNextListeners()
nextListeners.push(listener)
return function unsubscribe() {
if (!isSubscribed) {
return
}
isSubscribed = false
ensureCanMutateNextListeners()
const index = nextListeners.indexOf(listener)
nextListeners.splice(index, 1)
}
}複製代碼
3.派發用戶傳遞的動做。
function dispatch(action) {
//檢驗是否是個純對象。
if (!isPlainObject(action)) {
throw new Error(
'Actions must be plain objects. ' +
'Use custom middleware for async actions.'
)
}
//傳入參數action.type必須有值
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
//currentReducer是用戶傳進來的reducer,其實就是調用reducer
//兩個參數是currentState,當前狀態,行動。
//返回一個新的state,並存入currentState變量內
currentState = currentReducer(currentState, action)
} finally {
//try執行結束後,重置isDispatching狀態
isDispatching = false
}
//觸發subscribe訂閱函數
const listeners = currentListeners = nextListeners
for (let i = 0; i < listeners.length; i++) {
const listener = listeners[i]
listener()
}
//返回action,很重要,對於中間件來講
return action
}
複製代碼
至此,經常使用api 都已經定義完了。最重要的,初始化state
dispatch({ type: ActionTypes.INIT })複製代碼
源碼結束。
const reduxLib = require("redux")
const createStore = reduxLib.createStore
//定義了個reducer
function testReducer(state={total:0},action){
if(action.type == 'add'){
var total = state.total + 1
return Object.assign({},state,{total:total})
}else{
return state
}
}複製代碼
//當咱們不須要預知state,和enhancer時,一個reducer就夠了
let store = createStore(testReducer)複製代碼
//基本代碼寫完了,不知道源碼裏dispatch({ type: ActionTypes.INIT })這句還有沒有忘記//呢?當建立倉庫時,源碼手動觸發了dispatch,這裏面作什麼了?看上文dispatch定義。//testReducer(undefined,{ type: ActionTypes.INIT })返回值賦值給currenState.
var initState = store.getState();//拿到是撒?{total:0},是傳入reducer參數state的默認值;
console.log('initState',initState)複製代碼
store.subscribe(function(){
var state = store.getState()
console.log(state)
})複製代碼
for(var i = 0 ; i< 10 ; i++){
store.dispatch({
type:'add'
})
}複製代碼
//控臺截圖,是否是恍然大霧。。。
createStore 第二個參數時,是一個對象,最好和reducer裏的state數據模型保持一致。依我上例,繼續說,源碼dispatch({ type: ActionTypes.INIT }),會調用
node
let preloadedState = {
total:0
}
let store = createStore(testReducer,preloadedState);
console.log(store.getState()) //拿到的是preloadedState複製代碼