隨着應用程序單頁面需求的愈來愈複雜,應用狀態的管理也變得愈來愈混亂。應用的狀態不只包括從服務器獲取的數據,還包括本地建立的數據,以及反應本地UI狀態的數據,而Redux正是爲解決這一複雜問題而存在的。設計模式
用Redux官網的話來歸納什麼是Redux:Redux是針對JavaScript應用的可預測狀態容器。bash
這句話雖然簡短,但實際上是有幾個涵義的:服務器
有些人可能會認爲Redux一開始就是Facebook所建立的項目,其實否則,它主要是由Dan Abramov所開始的一個項目,Dan Abramov進入Facebook的React核心小組工做是最近的事情。在此以前,他還有建立另外還有其餘相關項目,像React Hot Loader、React DnD,可能比當時的Redux項目還更廣爲人知,在Facebook發表Flux架構不久以後,許多Flux架構的相似函數庫/框架,不管是增強版、進化版、大改版等等很是的多。Redux一開始的對外演示的大型活動,是在2015年的React-Europe研討會,視頻Live React: Hot Reloading with Time Travel。在視頻中就有一個簡單的說明,Redux用了"Flux + Elm"的概念。網絡
固然除了Flux與Elm以外,還有其餘的主要像RxJS中的概念與設計方式,Redux融合了各家的技術於一身,除了更理想的使用在Flux要解決的問題上以外,更延伸了一些不一樣的設計方式。可是對初學者來講,它也不容易學習,網絡上經常見到初學者報怨Redux實在有夠難學,這也並非徹底是Redux的問題,基本上來講Flux的架構本來就不是很容易理解,Redux還簡化了Flux的流程與開發方式。架構
因此咱們要理解Redux是什麼,咱們開始能夠從這Flux與Elm兩大基礎來理解,如下分別說明一些基本的概念。app
不管是Flux或其餘以Flux架構爲基礎延伸發展的函數庫(Alt、Reflux、Redux...)都是爲了要解決同一個問題,這個問題在React應用規模化時會很是明顯,簡單以一句話來講就是:應用程序領域(app domain)的狀態 - 簡稱爲App state。框架
應用程序都須要有App state(應用程序狀態),不管是在一個須要用戶登陸的應用,要有全局的記錄着用戶登陸的狀態,或是在應用程序中不一樣操做介面(組件)或各類功能上的數據溝通,都須要用到它。若是你已經有一些程序語言或應用的開發經驗,你應該知道這會像是MVC設計模式中的Model(模型)部份該做的事情。dom
React應用爲何會出現這個問題?緣由主要是來自React組件的自己設計形成的。React被設計爲一個類似於MVC架構中的View(視圖)的函數庫,固然實際上它能夠做的事情比MVC中的View(視圖)還要更多,但本質上的確React不是一個完整的應用程序開發框架,裏面沒有額外的架構能夠做相似Model(模型)或Controller(控制器)的事情。對小型的組件或應用而言,應用的數據都包含在裏面,也就是在View(視圖)之中。函數
有學過React的一些基礎的開發者應該會知道,在React中的組件是沒法直接更動state(狀態)的包含值,要透過setState方法來進行更動,這有很大的緣由是爲了Virtual DOM(虛擬DOM)的所設計,這是其中一點。另外在組件的樹狀階層結構,父組件(擁有者)與子組件(被擁有者)的關係上,子組件是隻能由父組件以props(屬性)來傳遞屬性值,子組件本身自己沒法更改本身的props,這也是爲何一開始在學習React時,都會看到大部份的例子只有在最上層的組件有state,並且都是由它來負責進行當數據改變時的從新渲染工做,子組件一般只有負責呈現數據。工具
固然,有一個很技巧性的方式,是把父組件中的方法聲明由props傳遞給子組件,而後在子組件觸發事件時,調用這個父組件的方法,以此來達到子組件對父組件的溝通,間接來更動父組件中的state。不過這個做法並不直覺,須要事先規範好兩邊的方法。在簡單的應用程序中,這溝通方式還可行,但若是是在有複雜的組件嵌套階層結構時,例如層級不少或是不一樣樹狀結構中的子組件要互相溝通時,這個做法是派不上用場的。
在複雜的組件樹狀結構時,惟一能做的方式,就是要將整個應用程序的數據整合在一塊兒,而後獨立出來,也就是整個應用程序領域的數據部份。另外還須要對於數據的全部更動方式,也要獨立出來。這二者組合在一塊兒,就是稱之爲"應用程序領域的狀態",爲了區分組件中的狀態(state),這個做爲應用程序領域的持久性數據集合,會被稱爲store(存儲)。
store(存儲)並非只有應用程序單純的數據集合而已,它還包含了全部對數據的變動方法。
store(存儲)的角色並不是只是組件中的state(狀態)而已,它也不會只有單純的記錄數據,可能在現今的每種不一樣的Flux延伸的函數庫,對於store的定義與設計都有所不一樣。在Flux的架構中的store中,它包含了對數據更動的函數/方法,Flux稱這些函數/方法爲"存儲查詢(Store Queries)",也把它的角色定位爲相似傳統MVC的Model(模型),但與傳統的Model(模型)最大明顯不一樣之處的是,store只能透過Action(動做)以"間接"的方式來自我刷新。
store的設計能夠解決應用程序的狀態存放與更動的問題,但它還不能完整的解決整個問題,只是一個開端。最困難的地方在於,要如何在觸發動做時,進行store(存儲)的更動查詢,以及進行呈現數據的更動與最後做整個應用程序的渲染。這一連串的步驟,整合爲一個數據流(Data Flow),Flux的名稱來由其實就是拉丁文中的Flow,Flux用單向(unidirectional)數據流來設計整個數據流的運做,也就是說整個數據的流動方向都是一致的,從在網頁上呈現的操做介面組件,被觸發事件後,傳送動做到發送器,再到store,最後進行整個應用的從新渲染,都是往單一個方向運行。
因此說,單向數據流是Flux架構的核心設計。下面是Flux簡單的流程示意圖:
這個數據流的位於最中心的設計是一個AppDispatcher(應用發送器),你能夠把它想成是個發送中心,不論來自組件何處的動做都須要通過它來發送。每一個store會在AppDispatcher上註冊它本身,提供一個callback(回調),當有動做(action)發生時,AppDispatcher(應用發送器)會用這個回調函數通知store。
因爲每一個Action(動做)只是一個單純的對象,包含actionType(動做類型)與數據(一般稱爲payload),咱們會另外須要Action Creator(動做建立器),它們是一些輔助函數,除了建立動做外也會把動做傳給Dispatcher(發送器),也就是調用Dispatcher(發送器)中的dispatch方法。
Dispatcher(發送器)的用途就是把接收到的actionType與數據(payload),廣播給全部註冊的callbacks。它這個設計並不是是首創的,這在設計模式中相似於pub-sub(發佈-訂閱)系統,Dispatcher則是相似Eventbus的概念。Dispatcher類的設計很簡單,其中有兩個核心的方法,這兩個是互爲相關的函數:
在數據流的最後,store要觸發最上層組件的setState,而後進行總體React的從新渲染工做。Flux提出的方式是一種自訂事件的監聽方式,把store用EventEmitter.prototype對象進行拓展,讓store具備監聽事件的能力,而後在最上層組件中的生命週期中,加入有更動時的監聽事件。這是因爲JavaScript中內建的Event、CustomEvent等介面,以及addListener、dispatch等方法,只能實做在具備事件介面的網頁DOM元素上。單純在JavaScript的對象上是沒有辦法使用,要靠額外的函數庫才能這樣做,這是必定要使用相似像EventEmitter這種函數庫的主要緣由。
不過,你可能會以爲爲何不乾脆一點直接對store上面做更動就行了,必定要拐這麼大一個彎,透過Action(動做)"間接"的方式來做自我刷新?
我想緣由之一,是要標準化Action(動做)的規格,也就是全部在應用程序中的組件,都得要按照這些動做來觸發事件,發送器中註冊的callbacks(回調)也是要寫成處理同一種規格的動做。Action(動做)主要由type(類型)與payload(有效數據)組成,Flux Standard Action(Flux標準動做)就是提出來要標準化Action(動做)的格式,有了統一格式的Action對象,在刷新數據時全部刷新方式會具統一性,這樣Flux纔有辦法把整個數據流運做完成一個循環再接着下一個。就像網絡的傳輸協定同樣,數據的格式與運做的流程,都有標準的規範,不是隨隨便便就能夠進行傳輸。固然還有一些其它的緣由,例如要避免Event Chains(事件連鎖)的發生。
其整個流程能夠用下面的方式表示:
事件觸發 ->
由Action Creator調用Dispatcher.dispatch(action) ->
Dispatcher調用已註冊的回調(callback) ->
調用對應的存儲查詢(Store Queries) ->
觸發Store更動事件 ->
進行整個應用的從新渲染
複製代碼
總結來講,Flux使用了單向數據流的設計架構,是爲了要解決React的應用程序領域狀態的問題。Flux的實做並不容易,有許多實做上的細節與開發步驟上都有分割不明確的問題,因此在此並不討論Flux的實做部份。在Flux發表以後(約爲2014年中),陸陸續續出現了許多函數庫與框架,都是基於Flux的基本設計概念,都是爲了要改善、簡化或自動化其中的實做步驟爲主,而Redux也是其中一套。在通過一段時間以後,目前較熱門的與較多人使用的,就屬Redux,它有不少的設計概念都來自於Flux,能多加理解Flux的基本設計概念,對於學習Redux是絕對有幫助的。
或許你有聽過函數式程序開發(functional programming, FP)的開發風格,FP是什麼?用下面的一句話來講明,摘譯自這篇教程文檔: 函數式程序開發就是隻使用"純粹函數"與"不可改變的值"來撰寫軟件應用的一種方式。
FP是現今至關熱門的一種程序開發風格,在很早以前就已經有一些純函數式程序開發的語言例如Haskell與OCaml,Elm也是一個純函數式程序開發的語言,它是一個很年輕的語言,Elm是專門用來開發網站應用程序的程序語言,最終編譯爲JavaScript在網頁上運行,它與JavaScript語言有多差別很大的設計,例如:
React與Flux中有許多設計,都有應用到FP的設計,與Elm中一部份設計至關相似。而Redux又使用更多Elm中的設計,尤爲是Elm-Architecture而來的,例如:
說明:Redux做者使用了FP(函數式程序開發)與Elm的架構,改進或簡化本來的Flux架構。
Redux是目前最熱門的、最多人使用的Flux架構類的函數庫,雖然Redux也能夠用於其餘的函數庫,但基本上它是專門爲了React應用所打造的。若是你真的要學會React,並用它來開發一個稍有規模的應用,學習Redux說是一條必經之路,固然也有其餘的Flux架構類函數庫能夠選擇,不一樣的函數庫有可能使用的解決方式與樣式相差會很是大。目前來講Redux的開發社羣是最龐大也是最活躍的,並且不見得其餘的函數庫就會更容易學習與使用,畢竟用得人多,你會遇到的問題大概都有人遇過,也都能找獲得解決方式,這是開源碼生態圈的紅利。
Redux會受歡迎不是沒有緣由的,如下分析幾個Redux的優勢:
Redux不一樣於Flux架構,它改採幾乎是純FP(函數式程序開發)的解決方式,目的是爲了要簡化Flux中數據流的處理實做,也的確能夠與React中的組件渲染配合得很好,這證實了它是找到了一個較爲理想的與React應用能密切合做的解決方式。FP(函數式程序開發)也是目前JavaScript界的熱門主題,Redux也所以吸引到很多開發者的目光。
Redux一開始就附了時光旅行調試工具與熱從新加載(hot reloading)的工具來提高開發體驗,這對開發者有很大的吸引力,這也表明在Redux應用上的數據變更,能夠更容易的測試與調試,這是其餘Flux架構類函數庫或框架中所沒有的見到的。
Redux一開始的版本只有99行代碼,這可能比一開始的Flux架構使用的API更要少,不過代碼少不見得概念就簡單,FP的撰寫風格多半追求的是更簡短的代碼,這須要高超的技巧、深度的概念與很多的基礎。Redux一開始就能夠很容易的使用於服務器端渲染,並且也不限於使用於React應用上,這也吸引了更多的開發者使用意願。
Redux做者一開始就撰寫很是多的文件與教程,讓許多開發者能更快捷地掌握Redux的應用技術,Redux做者也是技術討論區的常客,經常能夠看到他在討論區上回覆相關的問題。Redux的項目也是至關活躍的,有很是多的參與者在討論與解決問題,對於重大效能/臭蟲問題也是很快捷地解決。