Redux概念之一: Redux簡介

Redux的官網中用一句話來講明Redux是什麼:html

Redux是針對JavaScript應用的可預測狀態容器react

這句話雖然簡短,實際上是有幾個涵義的:git

  • 可預測的(predictable): 由於Redux用了reducer與純函數(pure function)的概念,每一個新的state都會由舊的state建來一個全新的state,這樣能夠做所謂的時光旅行調試。所以,全部的狀態修改都是"可預測的"。github

  • 狀態容器(state container): state是集中在單一個對象樹狀結構下的單一storestore便是應用程序領域(app domain)的狀態集合。redux

  • JavaScript應用: 這說明Redux並非單指設計給React用的,它是獨立的一個函數庫,可通用於各類JavaScript應用。設計模式

有些人可能會認爲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"的概念。服務器

Redux = Flux + Elm網絡

固然除了Flux與Elm以外,還有其餘的主要像RxJS中的概念與設計方式,Redux融合了各家的技術於一身,除了更理想的使用在Flux要解決的問題上以外,更延伸了一些不一樣的設計方式。可是對初學者來講,它也不容易學習,網絡上經常見到初學者報怨Redux實在有夠難學,這也並非徹底是Redux的問題,基本上來講Flux的架構本來就不是很容易理解,Redux還簡化了Flux的流程與開發方式。架構

因此咱們要理解Redux是什麼,咱們開始能夠從這Flux與Elm兩大基礎來理解,如下分別說明一些基本的概念。app

Flux

不管是Flux或其餘以Flux架構爲基礎延伸發展的函數庫(Alt、Reflux、Redux...)都是爲了要解決同一個問題,這個問題在React應用規模化時會很是明顯,簡單以一句話來講就是:

應用程序領域(app domain)的狀態 - 簡稱爲App state

應用程序都須要有App state(應用程序狀態),不管是在一個須要用戶登陸的應用,要有全局的記錄着用戶登陸的狀態,或是在應用程序中不一樣操做介面(組件)或各類功能上的數據溝通,都須要用到它。若是你已經有一些程序語言或應用的開發經驗,你應該知道這會像是MVC設計模式中的Model(模型)部份該做的事情。

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官網:

flux diagram

這個數據流的位於最中心的設計是一個AppDispatcher(應用發送器),你能夠把它想成是個發送中心,不論來自組件何處的動做都須要通過它來發送。每一個store會在AppDispatcher上註冊它本身,提供一個callback(回調),當有動做(action)發生時,AppDispatcher(應用發送器)會用這個回調函數通知store

因爲每一個Action(動做)只是一個單純的對象,包含actionType(動做類型)與數據(一般稱爲payload),咱們會另外須要Action Creator(動做建立器),它們是一些輔助函數,除了建立動做外也會把動做傳給Dispatcher(發送器),也就是調用Dispatcher(發送器)中的dispatch方法。

注: Payload用在計算機科學的意思,是指在數據傳輸時的"有效數據"部份,也就是不包含傳輸時的頭部信息或metadata等等用於傳輸其餘數據。它的英文本來是指是飛彈或火箭的搭載的真正有效的負載部份,例如炸藥或核子彈頭,另外的不屬於payload的部份固然就是火箭傳送時用的燃料或控制零件。

Dispatcher(發送器)的用途就是把接收到的actionType與數據(payload),廣播給全部註冊的callbacks。它這個設計並不是是首創的,這在設計模式中相似於pub-sub(發佈-訂閱)系統,Dispatcher則是相似Eventbus的概念。Dispatcher類的設計很簡單,其中有兩個核心的方法,這兩個是互爲相關的函數:

  • dispatch 發送payload(至關於動做)給全部註冊的callbacks。組件觸發事件時用這個方式來發送動做。

  • register 註冊在全部payload(至關於動做)發送時要調用的callbacks(回調)。這些callbacks(回調)就是上面說的會用來更動store的Store Queries(存儲查詢)。

在數據流的最後,store要觸發最上層組件的setState,而後進行總體React的從新渲染工做。Flux提出的方式是一種自訂事件的監聽方式,把storeEventEmitter.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官網:

總結來講,Flux使用了單向數據流的設計架構,是爲了要解決React的應用程序領域狀態的問題。Flux的實做並不容易,有許多實做上的細節與開發步驟上都有分割不明確的問題,因此在此並不討論Flux的實做部份。在Flux發表以後(約爲2014年中),陸陸續續出現了許多函數庫與框架,都是基於Flux的基本設計概念,都是爲了要改善、簡化或自動化其中的實做步驟爲主,而Redux也是其中一套。在通過一段時間以後,目前較熱門的與較多人使用的,就屬Redux,它有不少的設計概念都來自於Flux,能多加理解Flux的基本設計概念,對於學習Redux是絕對有幫助的。

Elm

或許你有聽過函數式程序開發(functional programming, FP)的開發風格,FP是什麼?用下面的一句話來講明,摘譯自這篇教程文檔:

函數式程序開發就是隻使用"純粹函數"與"不可改變的值"來撰寫軟件應用的一種方式

FP是現今至關熱門的一種程序開發風格,在很早以前就已經有一些純函數式程序開發的語言例如Haskell與OCaml,Elm也是一個純函數式程序開發的語言,它是一個很年輕的語言,Elm是專門用來開發網站應用程序的程序語言,最終編譯爲JavaScript在網頁上運行,它與JavaScript語言有多差別很大的設計,例如:

  • Elm是強(靜態)數據類型的,它的數據類型也滿多樣的

  • Elm是純FP的語言

  • Elm-Architecture是包含在Elm的應用框架,它是單向數據流的架構

React與Flux中有許多設計,都有應用到FP的設計,與Elm中一部份設計至關相似。而Redux又使用更多Elm中的設計,尤爲是Elm-Architecture而來的,例如:

  • 不可改變性(Immutability): 全部的值在Elm中都是不可改變的,Redux中的純函數(pure function)與Reducer的設計很相似,React的設計中也有這類的概念

  • 時光旅行調試(Time Traveling Debugger): 在Elm有這個設計,Redux學了過來

Redux做者使用了FP(函數式程序開發)與Elm的架構,改進或簡化本來的Flux架構

爲什麼要學習Redux & Redux的優勢

Redux是目前最熱門的、最多人使用的Flux架構類的函數庫,雖然Redux也能夠用於其餘的函數庫,但基本上它是專門爲了React應用所打造的。若是你真的要學會React,並用它來開發一個稍有規模的應用,學習Redux說是一條必經之路,固然也有其餘的Flux架構類函數庫能夠選擇,不一樣的函數庫有可能使用的解決方式與樣式相差會很是大。目前來講Redux的開發社羣是最龐大也是最活躍的,並且不見得其餘的函數庫就會更容易學習與使用,畢竟用得人多,你會遇到的問題大概都有人遇過,也都能找獲得解決方式,這是開源碼生態圈的紅利。

Redux會受歡迎不是沒有緣由的,如下分析幾個Redux的優勢:

使用了FP(函數式程序開發)與React能夠配合得很好

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的項目也是至關活躍的,有很是多的參與者在討論與解決問題,對於重大效能/臭蟲問題也是很快捷地解決。

相關文章
相關標籤/搜索