隨着 JavaScript 單頁應用開發日趨複雜,JavaScript 須要管理比任什麼時候候都要多的 state (狀態)。 這些 state 可能包括服務器響應、緩存數據、本地生成還沒有持久化到服務器的數據,也包括 UI 狀態,如激活的路由,被選中的標籤,是否顯示加載動效或者分頁器等等。
管理不斷變化的 state 很是困難。若是一個 model 的變化會引發另外一個 model 變化,那麼當 view 變化時,就可能引發對應 model 以及另外一個 model 的變化,依次地,可能會引發另外一個 view 的變化。直至你搞不清楚到底發生了什麼。state 在何時,因爲什麼緣由,如何變化已然不受控制。 當系統變得錯綜複雜的時候,想重現問題或者添加新功能就會變得舉步維艱。
Redux的設計借鑑Flux、 Elm、Immutable,它的出現就是爲了解決state裏的數據問題。Redux和Flux的主要區別是Redux裏面是單一的數據源設計,而Flux(或者Reflux)裏面有多個數據源。javascript
咱們知道,在React中,數據在組件中是單向流動的。數據從一個方向父組件流向子組件(經過props),因爲這個特徵,兩個非父子關係的組件(或者稱做兄弟組件)之間的通訊並非那麼清楚。
React並不建議直接採用組件到組件的通訊方式,儘管它有一些特性能夠支持這麼作(好比先將子組件的值傳遞給父組件,而後再由父組件在分發給指定的子組件)。這被不少人認爲是糟糕的實踐方式,由於這樣的方式容易出錯並且會讓代碼向「拉麪」同樣不容易理解。
固然React也沒有直接建議如何去處理這種情形,如下是React的文檔中關於這部分的描述:html
對於非父子關係的組件,你能夠本身創建一個全局的事件系統,Flux的模式也是一種可行的方式。java
Redux的出現就讓這個問題的解決變得更加方便了。Redux提供一種存儲整個應用狀態到一個地方的解決方案(能夠理解爲統一狀態層),稱爲「store」,組件將狀態的變化轉發通知(dispatch)給store,而不是直接通知其它的組件。組件內部依賴的state的變化狀況能夠經過訂閱store來實現。
使用Redux,全部的組件都從store裏面獲取它們依賴的state,同時也須要將state的變化告知store。組件不須要關注在這個store裏面其它組件的state的變化狀況,Redux讓數據流變得更加簡單。這種思想最初來自Flux,它是一種和React相同的單向數據流的設計模式。
react
Redux有三大原則git
單一數據源的設計讓React的組件之間的通訊更加方便,同時也便於狀態的統一管理。
根據Redux的文檔,狀態變化的惟一方式是觸發一個action(一個能夠描述發生了什麼的對象),這意味着咱們不能直接的去修改狀態,取而代之的是咱們能夠經過轉發action去告訴store咱們有改變狀態的意圖。store對象提供了很是少的API,僅僅只有4個方法:github
store.dispatch(action) store.subscribe(listener) store.getState() replaceReducer(nextReducer)
經過這幾個API不難發現,store並無直接提供setState()方法。
另外,因爲它大量使用 pure function 和 plain object 等概念(reducer 和 action creator 是 pure function,state 和 action 是 plain object)這對於項目的穩定性會是很是好的保證。ajax
一個action的例子:數據庫
var action = { type: 'ADD_USER', user: {name: 'Dan'} }; // 假設store對象已經經過Redux.createStore()建立 store.dispatch(action);
這段代碼中,經過dispatch() 方法將action傳遞給了store。Action 本質上是 JavaScript 普通對象。咱們約定,action 內必須使用一個字符串類型的 type 字段來表示將要執行的動做。多數狀況下,type 會被定義成字符串常量。當應用規模愈來愈大時,建議使用單獨的模塊或文件來存放 action。redux
import { ADD_TODO, REMOVE_TODO } from '../actionTypes'
前面描述過,Redux不容許直接去改變state,必須經過轉發action來告訴store有這個意圖要去改變這個狀態。reducer正是扮演處理轉發過來的action的意圖的函數而且能夠改變狀態的角色。一個reducer接受當前的state做爲參數,經過返回新的state去改變原有的state:設計模式
var someReducer = function(state, action) { ... return state; }
因爲reducer是純函數,須要注意:
使用Redux.createStore()來建立一個store,而且將全部的reducers做爲參數傳遞給它,此處以一個reducer爲例子:
var userReducer = function(state=[], action) { if (action.type === 'ADD_USER') { var newState = state.concat([action.user]); return newState; } return state; } // 建立一個store,而且將reducer做爲參數傳遞給它 var store = Redux.createStore(userReducer); // 將action傳遞給store,告訴store咱們有改變狀態的意向 store.dispatch({ type: 'ADD_USER', user: {name: 'cpselvis'} });
上述代碼運行後發生的事情:
經過這段代碼能夠發現:reducer函數實際上被執行了2次,一次是store建立的時候,一次是action被轉發以後。另外須要注意:Redux但願reducer函數老是返回一個新的狀態。這時的結果:
store.getState(); // => [{name: 'cpselvis'}]
經過這個例子,能夠總結出Redux的工做流程如圖:
到這裏,component -> action -> store -> reducer -> state 的單向數據流的問題就講完了。歸納的說就是:React組件裏面獲取了數據以後(好比ajax請求),而後建立一個action通知store我有這個想改變state的意圖,而後reducers(一個action可能對應多個reducer,能夠理解爲action爲訂閱的主題,可能有多個訂閱者)來處理這個意圖而且返回新的state,接下來store會收集到全部的reducer的state,最後更新state。