摘要:應(yīng)用這說明并不是單指設(shè)計給用的,它是獨立的一個函數(shù)庫,可通用于各種應(yīng)用。在數(shù)據(jù)流的最后,要觸發(fā)最上層組件的,然后進行整體的重新渲染工作。單純在的對象上是沒有辦法使用,要靠額外的函數(shù)庫才能這樣作,這是一定要使用類似像這種函數(shù)庫的主要原因。
Redux的官網(wǎng)中用一句話來說明Redux是什么:
Redux是針對JavaScript應(yīng)用的可預(yù)測狀態(tài)容器
這句話雖然簡短,其實是有幾個涵義的:
可預(yù)測的(predictable): 因為Redux用了reducer與純函數(shù)(pure function)的概念,每個新的state都會由舊的state建來一個全新的state,這樣可以作所謂的時光旅行調(diào)試。因此,所有的狀態(tài)修改都是"可預(yù)測的"。
狀態(tài)容器(state container): state是集中在單一個對象樹狀結(jié)構(gòu)下的單一store,store即是應(yīng)用程序領(lǐng)域(app domain)的狀態(tài)集合。
JavaScript應(yīng)用: 這說明Redux并不是單指設(shè)計給React用的,它是獨立的一個函數(shù)庫,可通用于各種JavaScript應(yīng)用。
有些人可能會認為Redux一開始就是Facebook所創(chuàng)建的項目,其實不然,它主要是由Dan Abramov所開始的一個項目,Dan Abramov進入Facebook的React核心小組工作是最近的事情。在此之前,他還有創(chuàng)建另外還有其他相關(guān)項目,像React Hot Loader、React DnD,可能比當(dāng)時的Redux項目還更廣為人知,在Facebook發(fā)表Flux架構(gòu)不久之后,許多Flux架構(gòu)的類似函數(shù)庫/框架,不論是加強版、進化版、大改版等等非常的多。Redux一開始的對外演示的大型活動,是在2015年的React-Europe研討會,視頻Live React: Hot Reloading with Time Travel。在視頻中就有一個簡單的說明,Redux用了"Flux + Elm"的概念。
Redux = Flux + Elm
當(dāng)然除了Flux與Elm之外,還有其他的主要像RxJS中的概念與設(shè)計方式,Redux融合了各家的技術(shù)于一身,除了更理想的使用在Flux要解決的問題上之外,更延伸了一些不同的設(shè)計方式。但是對初學(xué)者來說,它也不容易學(xué)習(xí),網(wǎng)絡(luò)上常常見到初學(xué)者報怨Redux實在有夠難學(xué),這也并不是完全是Redux的問題,基本上來說Flux的架構(gòu)原本就不是很容易理解,Redux還簡化了Flux的流程與開發(fā)方式。
所以我們要理解Redux是什么,我們開始可以從這Flux與Elm兩大基礎(chǔ)來理解,以下分別說明一些基本的概念。
Flux不論是Flux或其他以Flux架構(gòu)為基礎(chǔ)延伸發(fā)展的函數(shù)庫(Alt、Reflux、Redux...)都是為了要解決同一個問題,這個問題在React應(yīng)用規(guī)?;瘯r會非常明顯,簡單以一句話來說就是:
應(yīng)用程序領(lǐng)域(app domain)的狀態(tài) - 簡稱為App state
應(yīng)用程序都需要有App state(應(yīng)用程序狀態(tài)),不論是在一個需要用戶登錄的應(yīng)用,要有全局的記錄著用戶登錄的狀態(tài),或是在應(yīng)用程序中不同操作介面(組件)或各種功能上的數(shù)據(jù)溝通,都需要用到它。如果你已經(jīng)有一些程序語言或應(yīng)用的開發(fā)經(jīng)驗,你應(yīng)該知道這會像是MVC設(shè)計模式中的Model(模型)部份該作的事情。
React應(yīng)用為什么會出現(xiàn)這個問題?原因主要是來自React組件的本身設(shè)計造成的。React被設(shè)計為一個相似于MVC架構(gòu)中的View(視圖)的函數(shù)庫,當(dāng)然實際上它可以作的事情比MVC中的View(視圖)還要更多,但本質(zhì)上的確React不是一個完整的應(yīng)用程序開發(fā)框架,里面沒有額外的架構(gòu)可以作類似Model(模型)或Controller(控制器)的事情。對小型的組件或應(yīng)用而言,應(yīng)用的數(shù)據(jù)都包含在里面,也就是在View(視圖)之中。
有學(xué)過React的一些基礎(chǔ)的開發(fā)者應(yīng)該會知道,在React中的組件是無法直接更動state(狀態(tài))的包含值,要透過setState方法來進行更動,這有很大的原因是為了Virtual DOM(虛擬DOM)的所設(shè)計,這是其中一點。另外在組件的樹狀階層結(jié)構(gòu),父組件(擁有者)與子組件(被擁有者)的關(guān)系上,子組件是只能由父組件以props(屬性)來傳遞屬性值,子組件自己本身無法更改自己的props,這也是為什么一開始在學(xué)習(xí)React時,都會看到大部份的例子只有在最上層的組件有state,而且都是由它來負責(zé)進行當(dāng)數(shù)據(jù)改變時的重新渲染工作,子組件通常只有負責(zé)呈現(xiàn)數(shù)據(jù)。
當(dāng)然,有一個很技巧性的方式,是把父組件中的方法聲明由props傳遞給子組件,然后在子組件觸發(fā)事件時,調(diào)用這個父組件的方法,以此來達到子組件對父組件的溝通,間接來更動父組件中的state。不過這個作法并不直覺,需要事先規(guī)范好兩邊的方法。在簡單的應(yīng)用程序中,這溝通方式還可行,但如果是在有復(fù)雜的組件嵌套階層結(jié)構(gòu)時,例如層級很多或是不同樹狀結(jié)構(gòu)中的子組件要互相溝通時,這個作法是派不上用場的。
在復(fù)雜的組件樹狀結(jié)構(gòu)時,唯一能作的方式,就是要將整個應(yīng)用程序的數(shù)據(jù)整合在一起,然后獨立出來,也就是整個應(yīng)用程序領(lǐng)域的數(shù)據(jù)部份。另外還需要對于數(shù)據(jù)的所有更動方式,也要獨立出來。這兩者組合在一起,就是稱之為"應(yīng)用程序領(lǐng)域的狀態(tài)",為了區(qū)分組件中的狀態(tài)(state),這個作為應(yīng)用程序領(lǐng)域的持久性數(shù)據(jù)集合,會被稱為store(存儲)。
store(存儲)并不是只有應(yīng)用程序單純的數(shù)據(jù)集合而已,它還包含了所有對數(shù)據(jù)的更動方法
store(存儲)的角色并非只是組件中的state(狀態(tài))而已,它也不會只有單純的記錄數(shù)據(jù),可能在現(xiàn)今的每種不同的Flux延伸的函數(shù)庫,對于store的定義與設(shè)計都有所不同。在Flux的架構(gòu)中的store中,它包含了對數(shù)據(jù)更動的函數(shù)/方法,F(xiàn)lux稱這些函數(shù)/方法為"存儲查詢(Store Queries)",也把它的角色定位為類似傳統(tǒng)MVC的Model(模型),但與傳統(tǒng)的Model(模型)最大明顯不同之處的是,store只能透過Action(動作)以"間接"的方式來自我刷新。
store的設(shè)計可以解決應(yīng)用程序的狀態(tài)存放與更動的問題,但它還不能完整的解決整個問題,只是一個開端。最困難的地方在于,要如何在觸發(fā)動作時,進行store(存儲)的更動查詢,以及進行呈現(xiàn)數(shù)據(jù)的更動與最后作整個應(yīng)用程序的渲染。這一連串的步驟,整合為一個數(shù)據(jù)流(Data Flow),F(xiàn)lux的名稱來由其實就是拉丁文中的Flow,F(xiàn)lux用單向(unidirectional)數(shù)據(jù)流來設(shè)計整個數(shù)據(jù)流的運作,也就是說整個數(shù)據(jù)的流動方向都是一致的,從在網(wǎng)頁上呈現(xiàn)的操作介面組件,被觸發(fā)事件后,傳送動作到發(fā)送器,再到store,最后進行整個應(yīng)用的重新渲染,都是往單一個方向運行。
單向數(shù)據(jù)流是Flux架構(gòu)的核心設(shè)計
下面是個簡單的流程示意圖,上面有標(biāo)出主要的參與成員,來自Flux官網(wǎng):
這個數(shù)據(jù)流的位于最中心的設(shè)計是一個AppDispatcher(應(yīng)用發(fā)送器),你可以把它想成是個發(fā)送中心,不論來自組件何處的動作都需要經(jīng)過它來發(fā)送。每個store會在AppDispatcher上注冊它自己,提供一個callback(回調(diào)),當(dāng)有動作(action)發(fā)生時,AppDispatcher(應(yīng)用發(fā)送器)會用這個回調(diào)函數(shù)通知store。
由于每個Action(動作)只是一個單純的對象,包含actionType(動作類型)與數(shù)據(jù)(通常稱為payload),我們會另外需要Action Creator(動作創(chuàng)建器),它們是一些輔助函數(shù),除了創(chuàng)建動作外也會把動作傳給Dispatcher(發(fā)送器),也就是調(diào)用Dispatcher(發(fā)送器)中的dispatch方法。
注: Payload用在計算機科學(xué)的意思,是指在數(shù)據(jù)傳輸時的"有效數(shù)據(jù)"部份,也就是不包含傳輸時的頭部信息或metadata等等用于傳輸其他數(shù)據(jù)。它的英文原本是指是飛彈或火箭的搭載的真正有效的負載部份,例如炸藥或核子彈頭,另外的不屬于payload的部份當(dāng)然就是火箭傳送時用的燃料或控制零件。
Dispatcher(發(fā)送器)的用途就是把接收到的actionType與數(shù)據(jù)(payload),廣播給所有注冊的callbacks。它這個設(shè)計并非是獨創(chuàng)的,這在設(shè)計模式中類似于pub-sub(發(fā)布-訂閱)系統(tǒng),Dispatcher則是類似Eventbus的概念。Dispatcher類的設(shè)計很簡單,其中有兩個核心的方法,這兩個是互為相關(guān)的函數(shù):
dispatch 發(fā)送payload(相當(dāng)于動作)給所有注冊的callbacks。組件觸發(fā)事件時用這個方式來發(fā)送動作。
register 注冊在所有payload(相當(dāng)于動作)發(fā)送時要調(diào)用的callbacks(回調(diào))。這些callbacks(回調(diào))就是上面說的會用來更動store的Store Queries(存儲查詢)。
在數(shù)據(jù)流的最后,store要觸發(fā)最上層組件的setState,然后進行整體React的重新渲染工作。Flux提出的方式是一種自訂事件的監(jiān)聽方式,把store用EventEmitter.prototype對象進行拓展,讓store具有監(jiān)聽事件的能力,然后在最上層組件中的生命周期中,加入有更動時的監(jiān)聽事件。這是由于JavaScript中內(nèi)建的Event、CustomEvent等介面,以及addListener、dispatch等方法,只能實作在具有事件介面的網(wǎng)頁DOM元素上。單純在JavaScript的對象上是沒有辦法使用,要靠額外的函數(shù)庫才能這樣作,這是一定要使用類似像EventEmitter這種函數(shù)庫的主要原因。
不過,你可能會覺得為什么不干脆一點直接對store上面作更動就好了,一定要拐這么大一個彎,透過Action(動作)"間接"的方式來作自我刷新?
我想原因之一,是要標(biāo)準(zhǔn)化Action(動作)的規(guī)格,也就是所有在應(yīng)用程序中的組件,都得要按照這些動作來觸發(fā)事件,發(fā)送器中注冊的callbacks(回調(diào))也是要寫成處理同一種規(guī)格的動作。Action(動作)主要由type(類型)與payload(有效數(shù)據(jù))組成,F(xiàn)lux Standard Action(Flux標(biāo)準(zhǔn)動作)就是提出來要標(biāo)準(zhǔn)化Action(動作)的格式,有了統(tǒng)一格式的Action對象,在刷新數(shù)據(jù)時所有刷新方式會具統(tǒng)一性,這樣Flux才有辦法把整個數(shù)據(jù)流運作完成一個循環(huán)再接著下一個。就像網(wǎng)絡(luò)的傳輸協(xié)定一樣,數(shù)據(jù)的格式與運作的流程,都有標(biāo)準(zhǔn)的規(guī)范,不是隨隨便便就可以進行傳輸。當(dāng)然還有一些其它的原因,例如要避免Event Chains(事件連鎖)的發(fā)生。
整個的數(shù)據(jù)運作流程,大概是像下面這樣:
事件觸發(fā) -> 由Action Creator調(diào)用Dispatcher.dispatch(action) -> Dispatcher調(diào)用已注冊的回調(diào)(callback) -> 調(diào)用對應(yīng)的存儲查詢(Store Queries) -> 觸發(fā)Store更動事件 -> 進行整個應(yīng)用的重新渲染
下面是整個流程的示意圖,來自Flux官網(wǎng):
總結(jié)來說,F(xiàn)lux使用了單向數(shù)據(jù)流的設(shè)計架構(gòu),是為了要解決React的應(yīng)用程序領(lǐng)域狀態(tài)的問題。Flux的實作并不容易,有許多實作上的細節(jié)與開發(fā)步驟上都有分割不明確的問題,所以在此并不討論Flux的實作部份。在Flux發(fā)表之后(約為2014年中),陸陸續(xù)續(xù)出現(xiàn)了許多函數(shù)庫與框架,都是基于Flux的基本設(shè)計概念,都是為了要改善、簡化或自動化其中的實作步驟為主,而Redux也是其中一套。在經(jīng)過一段時間之后,目前較熱門的與較多人使用的,就屬Redux,它有很多的設(shè)計概念都來自于Flux,能多加理解Flux的基本設(shè)計概念,對于學(xué)習(xí)Redux是絕對有幫助的。
Elm或許你有聽過函數(shù)式程序開發(fā)(functional programming, FP)的開發(fā)風(fēng)格,F(xiàn)P是什么?用下面的一句話來說明,摘譯自這篇教程文檔:
函數(shù)式程序開發(fā)就是只使用"純粹函數(shù)"與"不可改變的值"來撰寫軟件應(yīng)用的一種方式
FP是現(xiàn)今相當(dāng)熱門的一種程序開發(fā)風(fēng)格,在很早之前就已經(jīng)有一些純函數(shù)式程序開發(fā)的語言例如Haskell與OCaml,Elm也是一個純函數(shù)式程序開發(fā)的語言,它是一個很年輕的語言,Elm是專門用來開發(fā)網(wǎng)站應(yīng)用程序的程序語言,最終編譯為JavaScript在網(wǎng)頁上運行,它與JavaScript語言有多差異很大的設(shè)計,例如:
Elm是強(靜態(tài))數(shù)據(jù)類型的,它的數(shù)據(jù)類型也滿多樣的
Elm是純FP的語言
Elm-Architecture是包含在Elm的應(yīng)用框架,它是單向數(shù)據(jù)流的架構(gòu)
React與Flux中有許多設(shè)計,都有應(yīng)用到FP的設(shè)計,與Elm中一部份設(shè)計相當(dāng)類似。而Redux又使用更多Elm中的設(shè)計,尤其是Elm-Architecture而來的,例如:
不可改變性(Immutability): 所有的值在Elm中都是不可改變的,Redux中的純函數(shù)(pure function)與Reducer的設(shè)計很類似,React的設(shè)計中也有這類的概念
時光旅行調(diào)試(Time Traveling Debugger): 在Elm有這個設(shè)計,Redux學(xué)了過來
為何要學(xué)習(xí)Redux & Redux的優(yōu)點Redux作者使用了FP(函數(shù)式程序開發(fā))與Elm的架構(gòu),改進或簡化原本的Flux架構(gòu)
Redux是目前最熱門的、最多人使用的Flux架構(gòu)類的函數(shù)庫,雖然Redux也可以用于其他的函數(shù)庫,但基本上它是專門為了React應(yīng)用所打造的。如果你真的要學(xué)會React,并用它來開發(fā)一個稍有規(guī)模的應(yīng)用,學(xué)習(xí)Redux說是一條必經(jīng)之路,當(dāng)然也有其他的Flux架構(gòu)類函數(shù)庫可以選擇,不同的函數(shù)庫有可能使用的解決方式與樣式相差會非常大。目前來說Redux的開發(fā)社群是最龐大也是最活躍的,而且不見得其他的函數(shù)庫就會更容易學(xué)習(xí)與使用,畢竟用得人多,你會遇到的問題大概都有人遇過,也都能找得到解決方式,這是開源碼生態(tài)圈的紅利。
Redux會受歡迎不是沒有原因的,以下分析幾個Redux的優(yōu)點:
使用了FP(函數(shù)式程序開發(fā))與React可以配合得很好Redux不同于Flux架構(gòu),它改采幾乎是純FP(函數(shù)式程序開發(fā))的解決方式,目的是為了要簡化Flux中數(shù)據(jù)流的處理實作,也的確可以與React中的組件渲染配合得很好,這證明了它是找到了一個較為理想的與React應(yīng)用能密切合作的解決方式。FP(函數(shù)式程序開發(fā))也是目前JavaScript界的熱門主題,Redux也因此吸引到不少開發(fā)者的目光。
時光旅行調(diào)試/熱重新加載Redux一開始就附了時光旅行調(diào)試工具與熱重新加載(hot reloading)的工具來提升開發(fā)體驗,這對開發(fā)者有很大的吸引力,這也代表在Redux應(yīng)用上的數(shù)據(jù)變動,可以更容易的測試與調(diào)試,這是其他Flux架構(gòu)類函數(shù)庫或框架中所沒有的見到的。
更簡化的代碼,更多可能的延伸應(yīng)用Redux一開始的版本只有99行代碼,這可能比一開始的Flux架構(gòu)使用的API更要少,不過代碼少不見得概念就簡單,F(xiàn)P的撰寫風(fēng)格多半追求的是更簡短的代碼,這需要高超的技巧、深度的概念與不少的基礎(chǔ)。Redux一開始就可以很容易的使用于服務(wù)器端渲染,而且也不限于使用于React應(yīng)用上,這也吸引了更多的開發(fā)者使用意愿。
更多的文件,發(fā)展良好的生態(tài)圈Redux作者一開始就撰寫非常多的文件與教程,讓許多開發(fā)者能更快捷地掌握Redux的應(yīng)用技術(shù),Redux作者也是技術(shù)討論區(qū)的???,常??梢钥吹剿谟懻搮^(qū)上回覆相關(guān)的問題。Redux的項目也是相當(dāng)活躍的,有非常多的參與者在討論與解決問題,對于重大效能/臭蟲問題也是很快捷地解決。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/81351.html
摘要:是一個程序架構(gòu),源于提出的一種架構(gòu),然而,它不僅可以應(yīng)用于,還可以應(yīng)用于其他任何框架中。有以下職責(zé)維持應(yīng)用的提供方法獲取提供方法更新通過注冊監(jiān)聽器通過返回的函數(shù)注銷監(jiān)聽器。同時,的返回值實際上是一個函數(shù)可以解除監(jiān)聽。 Redux是一個程序架構(gòu),源于Flux(Facebook提出的一種架構(gòu)),然而,它不僅可以應(yīng)用于React,還可以應(yīng)用于其他任何框架中。值得一提的是,Redux的源代碼很...
摘要:在這篇文章中,分享了他如何克服恐懼并開始使用源代碼來提高他的知識和技能。不久之后,你正在閱讀的源代碼將引導(dǎo)您進入規(guī)范。 通過閱讀源碼來提高js知識 原文傳送門:《Improve Your JavaScript Knowledge By Reading Source Code》 showImg(https://segmentfault.com/img/remote/14600000197...
摘要:異步實現(xiàn)設(shè)計需要增加三種通知異步請求發(fā)起的異步請求成功的異步請求失敗的示例代碼如下返回參數(shù)完全可以自定義。這種分別在請求開始前,請求成功后,請求失敗后發(fā)送。表示數(shù)據(jù)的有效性,他的作用是在異步請求發(fā)送失敗后,告訴當(dāng)前的數(shù)據(jù)是過時的數(shù)據(jù)。 說明:對Redux不了解的同學(xué)可先看看這篇文章Redux技術(shù)架構(gòu)簡介(一) 前言 這里說的Redux異步實現(xiàn),是專指Redux中的異步Action實現(xiàn),...
摘要:作為目前最火的模式實現(xiàn)之一,它有很多的點值得研究。這個函數(shù)既然要用于,也就是說它接收一個形式為的函數(shù),對其一層層嵌套形式為。這個會在開始時發(fā)起一個,并在這個時發(fā)起另一個成功或失敗的。為了方便起見,會返回這個讓調(diào)用者可以等待。 Redux作為目前最火的Flux模式實現(xiàn)之一,它有很多的點值得研究。今天我們首先來看看它的Middleware。 熟悉Express或者koa的朋友對Middle...
摘要:在方法中處理數(shù)據(jù)有三不同的角色派發(fā)器儲存視圖層我們的組件的主要思想是有一個單一源儲存他們只能通過觸發(fā)更新。這些操作負責(zé)調(diào)用派發(fā)器可以訂閱更改并相應(yīng)地更新自己的數(shù)據(jù)。與不同不使用派發(fā)器而是使用純函數(shù)來定義數(shù)據(jù)變異函數(shù)。 本文轉(zhuǎn)載自:眾成翻譯譯者:iOSDevLog鏈接:http://www.zcfy.cc/article/3812原文:https://www.fullstackreact...
閱讀 3063·2023-04-26 00:40
閱讀 2408·2021-09-27 13:47
閱讀 4267·2021-09-07 10:22
閱讀 2974·2021-09-06 15:02
閱讀 3322·2021-09-04 16:45
閱讀 2507·2021-08-11 10:23
閱讀 3612·2021-07-26 23:38
閱讀 2908·2019-08-30 15:54