狀態管理器這麼火,讓我們來做一個簡單的redux原理解析吧(vuex類似)

佩子發表於2018-08-16

redux狀態管理器,實質上就是一個單例模式。我們來實現一個簡單的redux模型,實現之前我們要先熟悉它的用法。

狀態管理器這麼火,讓我們來做一個簡單的redux原理解析吧(vuex類似)

  • Redux是將整個應用狀態儲存到到一個地方,稱為store裡面儲存一棵狀態樹(state tree)
  • 元件可以派發(dispatch)行為(action)給store,而不是直接通知其它元件
  • 其它元件可以通過訂閱store中的狀態(state)來重新整理自己的檢視.

下面我們按照這個思想來想想怎麼做。 我們來抽象一下,提取出最核心的思想,動用鬼斧神工畫個圖:

狀態管理器這麼火,讓我們來做一個簡單的redux原理解析吧(vuex類似)

用文字來描述一下,一個唯一的倉庫裡,有一個私有屬性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基本模型就做好了,有什麼不懂的可以提問喲~

相關文章