redux狀態管理器,實質上就是一個單例模式。我們來實現一個簡單的redux模型,實現之前我們要先熟悉它的用法。
- Redux是將整個應用狀態儲存到到一個地方,稱為store裡面儲存一棵狀態樹(state tree)
- 元件可以派發(dispatch)行為(action)給store,而不是直接通知其它元件
- 其它元件可以通過訂閱store中的狀態(state)來重新整理自己的檢視.
下面我們按照這個思想來想想怎麼做。 我們來抽象一下,提取出最核心的思想,動用鬼斧神工畫個圖:
用文字來描述一下,一個唯一的倉庫裡,有一個私有屬性state,倉庫由門衛大哥進行管理,所有對state的操作都要經過門衛大哥,外面的人無權直接對state進行操作,如果有進行訂閱,則在狀態改變後收到狀態改變事件。好了,我們按照這個思想來開始code吧
第一步:宣告一個物件
const state={ a: 1 }
第二步:將物件包裹起來,使其不可隨意訪問
function createStore(){ const state={ a: 1 } }
第三步:暴露出一個方法,使外部可以對狀態進行操作
function createStore() { let state={ a:1 }; function getState() { return state //此處直接將state返回,會使state引用地址暴露,從而被引用物件改變值 } return { getState } } let store = createStore() // 建立一個倉庫 let state = store.getState() // 獲取狀態state console.log(store.getState()) // 輸出{ a: 1 } state.a = 2 //將state a的值設定為2 console.log(state) // 輸出為{ a: 2 } console.log(store.getState()) // 此時倉庫中state的值也改變了,輸出為{ a: 2 }
所以我們將第六行
return state
替換為
return JSON.parse(JSON.stringify(state))
可以避免這個問題。
第四步:除了獲取狀態我們還需要操作狀態,暴露第二個方法,dispatch,順便將state的初始化進行一下優化
'use strict' function createStore() { let state; function getState() { return JSON.parse(JSON.stringify(state)) } function dispatch(action) { // 分發 state = reducer(state,action) // 接收當前 State 和Action作為引數,返回一個新的 State } dispatch({ type: '@@INIT' }) // 在建立倉庫的時候,初始化state的值 return { getState, dispatch } } let initState = { count: 0 } //處理器,接收二個引數 ,接收老狀態和action,返回新狀態 function reducer(state = initState, action) { // 如果state沒有值,預設值為initState //判斷動作的型別 switch (action.type) { case 'ADD_TODO': return { ...state, count: action.number }; //...state解構state所有屬性,count: action.number覆蓋前面的值 default: return state; } } let store = createStore() // 建立一個倉庫 let state = store.getState() // 獲取狀態state let action = { type: 'ADD_TODO', number: 1 }; store.dispatch(action); // 派發一個action,改變state的狀態 console.log(store.getState()) // 輸出{ count: 1 }
diapatch中執行我們定義的reducer處理器函式,增刪改查。例子演示了先建立一個倉庫,在建立新倉庫的時候初始化了state。然後diapatch一個action:ADD_TODO,執行的處理是改變count的值,返回一個新的state物件,最後我們可以看到輸出,原來的state在初始化後變成{ count: 0 },又在ADD_TODO後變成了{ count: 1 }。
reducer函式是我們在使用redux時需要自己定義的處理函式。
至此,我們已經實現了建立一個倉庫,並且可以自定義一些處理函式對state進行操作。還缺了什麼呢?在實際專案中,狀態改變後我們的大部分的元件需要立即得到新的狀態,然後根據狀態改變作出不同的處理。也就是說元件對state進行一個監聽,一旦state發生改變,立馬通知到對應的元件。讓我們來繼續實現吧。。。
第五步:增加一個訂閱功能subscribe
function createStore() {
let state;
let listeners = [];
function getState() {
return JSON.parse(JSON.stringify(state))
}
function dispatch(action) { // 分發
state = reducer(state,action); // 接收當前 State 和Action作為引數,返回一個新的 State
listeners.forEach(listener => listener()) // 一旦狀態改變,觸發所有的監聽函式,這裡需要優化,只有相關狀態改變才需要觸發
}
function subscribe(listener){ // 訂閱,如果需監聽狀態變化,將監聽函式傳過來
listeners.push(listener); // 儲存監聽函式到監聽陣列
return function () { // 返回取消訂閱的函式
listeners = listeners.filter(item => item != listener); // 過濾監聽函式
}
}
dispatch({ type: '@@INIT' }); // 在建立倉庫的時候,初始化state的值
return {
getState,
dispatch,
subscribe
}
}
/*這裡是分割線,上面一部分是倉庫定義,下面部分是使用方法*/
let initState = {
count: 0
}
//處理器,接收二個引數 ,接收老狀態和action,返回新狀態
function reducer(state = initState, action) { // 如果state沒有值,預設值為initState
//判斷動作的型別
switch (action.type) {
case 'ADD_TODO':
return { ...state, count: action.number }; //...state解構state所有屬性,count: action.number覆蓋前面的值
default:
return state;
}
}
let store = createStore() // 建立一個倉庫
let action = { // 定義一個action
type: 'ADD_TODO',
number: 1
};
let unADD = store.subscribe(function(){ // 監聽狀態改變
console.log('狀態改變了,現在的state為:') // 狀態改變了,現在的state為:
console.log(store.getState()) // { count: 1 }
})
store.dispatch(action); // 派發一個action,改變state的狀態
複製程式碼
鐺鐺鐺~,我們的redux基本模型就做好了,有什麼不懂的可以提問喲~