Redux入门之实现一个迷你版的Redux
Redux是一種數據架構模式,它可以用來管理應用的狀態。
之前一直在做Angular的項目,沒有使用到過Redux,對于Redux的使用場景和原理都不是很清楚,看資料時作者自己實現了一個Redux,在這里記錄一下,加深對Redux原理的理解。
一、基本原理
首先,我們要明白的是:
- 狀態的改變一定是有原因的,這個原因的表現叫作action。
- 有了action之后,狀態不可能自己就改變,需要我們去操作它,這個操作就是reducer函數。
- 操作狀態需要2個條件,之前的狀態和觸發操作的action,這個操作是為了改變狀態,使以這個操作返回一個新的狀態。
按照上面的說明,我們先定義一下action和reducer的接口。
?
1 // 首先,狀態改變一定是由action引起的,至于這個action是由什么觸發的(用戶點擊button、異步通信)我們不關心 2 export interface Action{ 3 // 在action中只有type是必須的,讓我們知道它是哪一類action(是用戶點擊button的action而不是異步通信的action) 4 type: string; 5 // 這個action可能需要帶一些數據 6 payload?: any; 7 } 8 // 觸發action意味著狀態要改變,那我們怎么修改狀態呢? 9 // 從最基本的來說,修改狀態我們需要知道兩樣東西: 以前的狀態和觸發的action 10 // 那么Reducer函數有2個參數:以前的狀態action和觸發的action,它還要返回一個新的狀態 11 export interface Reducer<T> { 12 (state: T, action: Action): T; 13 }?
根據接口我們來使用一下:
1 let reducer: Reducer<number> = (state: number, action: Action): number => { 2 // 使用switch來區分是什么action 3 switch(action.type) { 4 case 'ADD': 5 return state + action.payload; 6 case 'DEC': 7 return state - action.payload; 8 default: 9 // 有一些action我們不想讓它改變狀態,這里把原來的狀態返回回去 10 return state; 11 } 12 } 13 let addAction: Action = { 14 type: 'ADD', 15 payload: 5 16 } 17 let decAction: Action = { 18 type: 'DEC', 19 payload: 2 20 }?
可以看到,我們定義了一個怎么處理action使得狀態改變的函數。還定義了一個增加的action和減少的action。
下面我們來使用一下:
let state = 10; console.log(reducer(state, addAction)) // 15 console.log(reducer(state, decAction)) // 8?
?這里我們先觸發了一個加5的action,這時狀態變成了15,
然后我們觸發了一個減2的操作,因為我們并沒有保存剛才減5的后的狀態,所以這時的狀態還是10,最后的結果就變成了8,
這顯然不是我們需要的結果,我們想把狀態保存住,那么狀態保存在哪里呢?我們新建一個叫作store的容器(一個對象),它用來保存狀態state。
?
1 // 這是一個類,用它來生成保存狀態的容器, 2 export class Store<T> { 3 // 狀態是不能讓外界直接知道的 4 private _state: T; 5 // 生成這個容器時我們需要知道操作狀態的方法 6 constructor(private reducer: Reducer<T>) {} 7 // 外界從容器中得到當前狀態的途徑 8 public getState() { 9 return this._state; 10 } 11 // 狀態是保存在容器中的,如果外界發生了什么事情(action),想要改變狀態,這時需要有一個接口讓容器知道外界有需要改變狀態的事件發生了 12 public dispatch(action: Action) { 13 // 以前的狀態 + 觸發的action = 新的狀態 14 this._state = this.reducer(this._state, action); 15 } 16 }?
?我們來新建一個容器:
// 我們先新建一個容器 let store: Store<number> = new Store<number>(reducer);?
發生action時通過容器的dispatch通知reducer去操作狀態
1 store.dispatch(addAction); 2 console.log(store.getState()); // 15 3 store.dispatch(decAction); 4 console.log(store.getState()); // 13?
?可以看到,這里的狀態就被保存住了。
上面的就是我理解的Redux保存狀態的最基本的邏輯。
?
容器保存著狀態,外界想要改變和獲取狀態只能通過容器。
?獲取狀態是容易理解的,外界想要改變狀態時,要通知(調用dispatch方法)容器有一個action發生了,容器內部知道發生了action,它會結合以前的狀態和action產生新的狀態來更新自己保存的狀態。
(我覺得從代碼實現上是比較簡單的,但是想從原理上說清楚我是等級不夠啊)
二、優化
1、action生成器
上面的代碼中,沒一個action都要我們自己聲明的,比如如果想定義加1的action和加2的action,可以這樣寫:
1 let addAction1: Action = { 2 type: 'ADD', 3 payload: 1 4 } 5 let addAction2: Action = { 6 type: 'ADD', 7 payload: 2 8 } View Code?
這顯然不是好的體驗,可以定義action生成器,把一類的action使用工廠方法生成
1 function createAddAction(num: number): Action { 2 return { 3 type: 'ADD', 4 payload: num 5 } 6 }?
使用時就可以這樣:
store.dispatch(createAddAction(1)); store.dispatch(createAddAction(2));?
2、主動發出狀態的變化
我們現在在改變狀態后是從容器中拉取狀態的,有沒有辦法是狀態改變后容器自動推送出改變呢。
下面使用回調函數來實現容器的自動推送:
1 // 這是一個類,用它來生成保存狀態的容器, 2 export class Store<T> { 3 // 狀態是不能讓外界直接知道的 4 private _state: T; 5 private _listenCallback: ListenCallback[] = []; 6 // 生成這個容器時我們需要知道操作狀態的方法 7 constructor(private reducer: Reducer<T>) {} 8 // 外界從容器中得到當前狀態的途徑 9 public getState() { 10 return this._state; 11 } 12 // 外界添加回調函數,在狀態改變時會觸發回調,讓外界知道狀態已經改變 13 public subscribe(listenCallback: ListenCallback) { 14 // 添加回調 15 this._listenCallback.push(listenCallback); 16 // 給外界關閉通知的接口 17 return () => { 18 this._listenCallback = this._listenCallback.filter( 19 (l: ListenCallback) => l !== listenCallback 20 ); 21 } 22 } 23 // 狀態是保存在容器中的,如果外界發生了什么事情(action),想要改變狀態,這時需要有一個接口讓容器知道外界有需要改變狀態的事件發生了 24 public dispatch(action: Action) { 25 // 以前的狀態 + 觸發的action = 新的狀態 26 this._state = this.reducer(this._state, action); 27 // 通知外界狀態改變了 28 this._listenCallback.forEach( 29 (l: ListenCallback) => l() 30 ) 31 } 32 }
?
注意13行,這里提供了一個接口,讓外界可以知道狀態改變了,28行是狀態改變時通知外界。
可以這樣使用:
1 let unsubscribe = store.subscribe( 2 () => console.log(store.getState()) 3 ); 4 store.dispatch(createAddAction(1)); 5 6 store.dispatch(createAddAction(1)); 7 unsubscribe(); 8 store.dispatch(createAddAction(1));?
?完整的代碼可以在https://github.com/wangzting/miniRedux這里找到。
我在嘗試從原理出發而不是從代碼出發來解釋Redux,我想知道Redux的作者是怎么思考出這個數據架構的,他是怎么把簡單的道理用規范的代碼表現出來的,顯然,我做的不好。
任重而道遠,我會繼續努力。
?作成:2019-02-13
修改:
2019-02-13 添加碼源地址
參考:《Angular權威教程》
轉載于:https://www.cnblogs.com/wangtingnoblog/p/Redux.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的Redux入门之实现一个迷你版的Redux的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: cs20_8-1
- 下一篇: [BZOJ5292][BJOI2018]