經過Redux源碼學習基礎概念一:簡單例子入門

    最近公司有個項目使用react+redux來作前端部分的實現,正好有機會學習一下redux,也和小夥伴們分享一下學習的經驗。前端

首先聲明一下,這篇文章講的是Redux的基本概念和實現,不包括react-redux。react

源碼地址:https://github.com/lyc-chengzi/reactProjectjquery

首先說一下我理解的Redux:git

它只是一個管理數據的一個工具,幫助咱們建立app中惟一的一個數據結構的樹,而且按照約定的方法來管理這顆樹,讓咱們的數據的更改變爲可預測的。github

任何一個普通的框架,或者如angular, jquery等均可以依賴於這個數據結構,來作本身的事情。json

 

react-redux:redux

這個庫則是幫助咱們將react組件和redux建立的數據樹串聯起來,讓普通的react組件根據state來從新渲染。數據結構

之後可能也會有angular-redux, jquery-redux等等庫,幫助咱們實現其餘框架的ui渲染。閉包

 

好了,下面進入正題:app

Redux的運行原理

1. 先定義好咱們的reducer -> 2. 組裝reducer -> 3. 調用redux.createStore建立一個store -> 4. store調用dispatch方法 ->5. 觸發你寫的reducer -> 6. 返回新的state

舉一個簡單的例子,咱們的app就是一個計數器,實現加和減的功能,一個最簡單的數據結構:{counter: 0};下面開始按照上面的步驟實現

1. 先定義一個咱們的reducer,其實就是一個回調函數

 1 function counter(state = 0, action){
 2     switch (action.type){
 3         case 'counter_add':
 4             return ++state;
 5             break;
 6        
 7         default:
 8             return state;
 9     }
10 }

reducer固定會接收兩個參數,state和action。

reducer的做用就是接受一箇舊的state,而後內部加工處理後,返回一個新的state給redux,這就是reducer的職能:擴展或修改原有state並返回!

第一個參數state就是redux告訴咱們的更改前的數據,咱們以此爲基礎作一些操做。具體是那些操做,就經過第二個參數action告訴咱們。

如上面的代碼,經過action.type,咱們處理了counter_add action,即數字加1操做,咱們把state+1;其餘未知操做咱們直接返回原有state。

這樣一個最簡單的reducer就建立完了,是否是很簡單? 就是一個普通的回調函數

 

2. 組裝reducer

1 var app = function(state = {}, action){
2     return {counter: counter(state.counter, action)};
3 };

這一步的目的是返回一個根reducer,由於默認state爲undefined,因此咱們給state一個默認值{}。根reducer返回一個json對象,key爲名稱,value爲具體的實現reducer

3. 建立store

let store = redux.createStore(app);
console.log(store.getState());

 

簡單的2行代碼,經過咱們定義的根reducer,redux建立一個store對象返回給咱們。

咱們只能經過dispatch方法來改變整個app的state,調用getState方法查看初始化後的數據結構

4. 調用dispatch,來實現計數器增長

1 store.dispatch({type: 'counter_add'});
2 console.log(store.getState());

dispatch方法只接受一個action參數。

action爲一個json對象:必須包含type屬性,用來標識是哪個action,也能夠有其餘屬性做爲附加值傳遞到reducer

這裏咱們傳遞了'counter_add'告訴redux。

這個action會從你的根reducer一直傳遞下去,到末級reducer。只要咱們定義的reducer處理這個action,就會更新state。

而後咱們打印最新的state,以下

 

若是咱們要更新state,只能經過調用store.dispatch方法,傳遞action參數。而後redux會調用咱們的reducer來處理這個action,最後return 最新的state。

下面咱們經過源碼來看一下關鍵的兩個函數是如何運行的。

1. createStore

 1 function createStore(reducer, preloadedState, enhancer) {
 2      var currentReducer = reducer;
 3      var currentState = preloadedState;
 4      var currentListeners = [];
 5      var nextListeners = currentListeners;
 6      var isDispatching = false;
 7 
 8     dispatch({ type: ActionTypes.INIT });
 9 
10   return _ref2 = {
11     dispatch: dispatch,
12     subscribe: subscribe,
13     getState: getState,
14     replaceReducer: replaceReducer
15   }, _ref2[_symbolObservable2['default']] = observable, _ref2;
16 }

 

上面是createStore的關鍵代碼。

使用了閉包的技巧,隱藏了幾個關鍵變量:  

currentReducer=>咱們傳入的根reducer

currentState => 當前默認state,咱們默認爲一個空json對象{}

nextListeners和currentListeners用來保存監聽函數,當咱們調用dispatch方法時會觸發

isDispatching => 當前調度狀態,只有當前調度狀態是false時纔會執行dispatch方法

初始化完幾個關鍵內部變量後,執行了一次默認的dispatch方法,action.type爲reduxInit

最後返回了一個包裝對象,包含了對外公開的方法。咱們只能經過這幾個方法來操做內部的變量。

(雖然能夠var state= store.getState();獲取state以後直接修改,但千萬不要這麼作,否則redux也沒有意義了。我的認爲若是getState()返回一個clone的currentState會更好)

2.咱們來看一下dispatch都幹了些什麼

 1 function dispatch(action) {
 2     if (!(0, _isPlainObject2['default'])(action)) {
 3       throw new Error('Actions must be plain objects. ' + 'Use custom middleware for async actions.');
 4     }
 5 
 6     if (typeof action.type === 'undefined') {
 7       throw new Error('Actions may not have an undefined "type" property. ' + 'Have you misspelled a constant?');
 8     }
 9 
10     if (isDispatching) {
11       throw new Error('Reducers may not dispatch actions.');
12     }
13 
14     try {
15       isDispatching = true;
16       currentState = currentReducer(currentState, action);
17     } finally {
18       isDispatching = false;
19     }
20 
21     var listeners = currentListeners = nextListeners;
22     for (var i = 0; i < listeners.length; i++) {
23       listeners[i]();
24     }
25 
26     return action;
27   }

很是簡單,只是調用了你根reducer函數,而後將內部保存的當前state,和action傳了過去,剩下的都是你的reducer乾的事情了。

因此createStore默認調用了一次dispatch,action.type爲init,咱們的reducer沒有對應的處理方法,直接將默認的state返回了回去。

如今也就明白了爲何咱們的reducer爲何要在default的時候返回變化前的state。

因此總結一下redux,就是dispatch的過程,(由於createStore也是dispatch,不過是在內部調用的),每一次dispatch都會調用一次咱們的根reducer,而後從新構建一遍數據,

而後把新的數據保存起來。

 

到此咱們就把一個最簡單的redux例子學完了。下一篇將會介紹另外一種組裝reducer的方法:經過調用

redux.combineReducers

方法讓redux幫咱們構建數據結構,而且演示如何作多級的數據結構

相關文章
相關標籤/搜索