在WEB1.0時代,數據改變與頁面刷新的機制比較簡單粗暴:「後端改變state,前端整個頁面view刷新」;前端
web2.0時代,咱們但願:react
「改變state,view自動更新」web
瀏覽器裏的DOM tree克隆一份完整的鏡像到內存,也就是所謂的「virtual DOM」,編程
當頁面的state發生變化之後,根據最新的state從新生成一份virtual DOM(至關於在內存裏「刷新」整個頁面),將它和以前的virtual DOM作比對(diff),而後在瀏覽器裏只渲染被改變的那部份內容,這樣瀏覽器的性能損耗和用戶體驗不就都不成問題了嗎?redux
**在絕大多數的WEB開發中:**js引擎的性能和內存徹底沒有被充分利用,咱們正好能夠火力全開,利用js的這部分性能紅利,實現內存中virtual DOM的diff工做,完美!後端
react很是具備表達力的jsx語法和完善的模塊化結構,設計模式
view的組件化和模塊化很是有利於分工協做、代碼的積累複用以及單元測試,瀏覽器
伴隨着reactJS 前端框架的崛起,redux這些專一於管理state的輕量級框架橫空出世;bash
*因爲React的「state-view」模式可讓開發者的大腦獲得一種「單向流」的溫馨體驗。那爲何單向流的思惟狀態更加溫馨呢?前端框架
這是由於在單向流狀態下,要解決的問題如同一個函數映射,已知什麼(好比state)是固定不變的,要獲得什麼(好比view)是定義明確,而人的思惟很是習慣於這種定義明確的、沒有「分叉」和「環路」的函數式問題。
頁面呈現的state能夠經過模塊屬性(props)從父模塊傳遞到子模塊。這種"樹狀"分流機制,有點像植物將營養(state)從根部不斷運輸到細枝末葉的過程*
Flux思想:
flux設計模式就是解決以上model-view混亂=>
如今咱們又能夠從服務器端的MVC模式中得到靈感了!
由於咱們注意到,服務器端的controller一般也須要對不少Model產生修改,但在代碼結構中卻集中在一塊兒,沒有散落一地。緣由很簡單:
對比之下,咱們馬上發現上述代碼片段中前端MVC模式的「痛點」所在:不是MVC模式錯了,而是咱們壓根缺乏了一個和用戶交互行爲有關的action抽象!所以,對model的具體操做才無法從各個view組件中被剝離出來,放到一處。
參考http請求,咱們將要定義的action,須要一個typeName用來表示對model操做的意圖(相似於http請求的url路徑),還可能須要其餘字段,用來描述怎樣具體操做model(相似於http請求的參數)。
也就是說,當用戶在view上的交互行爲(例如點擊提交按鈕)應當引發Model發生變化時,咱們不直接修改model,而是簡單地dispatch一個action(其實跟常見的event機制沒有什麼區別)以表達修改model的意圖,這些action將被集中轉移給數據端(models),而後數據端會根據這些action作出須要的自我更新。同時,咱們考慮到react中view組件的樹狀分流結構,因此有以下圖所示:
稍微總結一下:從代碼層面而言,flux無非就是一個常見的event dispatcher,其目的是要將以往MVC中各個View組件內的controller代碼片段提取出來放到更加恰當的地方進行集中化管理,並從開發體驗上實現了溫馨清爽、容易駕馭的「單向流」模式。 因此我以爲,Flux與其說是對前端MVC模式的顛覆,倒不如說是對前端MVC思想的補充和優化。
但爲了區分於以往的MVC模式,並向facebook的貢獻表達敬意,後面咱們將把這種優化後的 Model-View-Controller 開發模式在React背景下正式稱爲Flux模式
問題:
React的能夠經過View Component把頁面呈現進行「原子化」拆分(即上圖中蘭色區域的樹狀分流結構);
Flux打通了State-View的任督二脈(綠色區域),並經過action抽象把用戶交互行爲
進行了「原子化」拆分;
複製代碼
那麼聯繫上面的圖示,咱們天然要問數據端(紫色區域)的處理,能否一樣被「原子化」拆分?
redux 中的reduce機制,將state端的數據處理進行‘原子化’拆分。redux是來自函數式編程(Functional Programming)的一朵奇葩,聽說頗有背景([參考連接](Prior Art | Redux) ) reducer,從代碼上說,其實就是一個函數,具備以下形式:
(previousState, action) => newState
複製代碼
reducer做爲一個函數,能夠根據web應用以前的狀態(previousState)和交互行爲(經過flux中提到的action來表徵),決定web應用的下一狀態(newState),從而實現state端的數據更新處理。這個函數行爲和大名鼎鼎的「Map-Reduce」概念中的Reduce操做很是相似,於是稱這個函數爲「Reducer」。
"shut up and show me the code" redux.js.org/basics/exam…
這裏不打算詳細講解Redux的具體使用,而只想經過一個Redux對state數據進行操做的代碼片段,管窺一下reducer機制對數據進行拆分和組裝的簡潔過程。代碼片段以下
回味一下,咱們應該能夠體會到,這種數據處理「原子化」拆分的方式和react中view組件的拆分有殊途同歸之妙,兩者都會造成一種「樹狀」分流結構(在react的view hierarchy中,數據經過props的直接賦值實現單向流;在redux的reducer hierarchy中,數據經過action的函數傳參實現單向流)。
visibilityFilter是和列表顯示狀態相關的另外一個reducer;combineReducers將visibilityFilter和todos合併爲整個應用的reducer,也就是todoApp。這個過程,從感受上也和react中view組件的合併過程很是相像。
createStore是一個工廠函數。經過它,todoApp(至關於一個數據處理的引擎)被裝配到整個應用的state容器,也就是store中。能夠經過store的getState方法獲取整個應用的state;同時,store也是一個event dispatcher,能夠經過其dispatch和subscribe方法,分別實現觸發action事件和註冊對action事件的響應函數。總言之,從概念上來講 Redux = Reducer + Flux
全體亮相
如今React開發模式中的幾個核心概念已經所有出場亮相。咱們俯瞰一下整個開發流程:首先,react框架爲咱們理順了 store --> view 的「單向」工做流(store是state的容器);而後,redux框架爲咱們理順了 view --> store 的**「單向」**工做流。而且,react和redux都以組件化的形式能夠將各自負責的功能進行靈活地組裝或拆分,最大程度上確保咱們「一次只須要專一於一個局部問題」。具體來講,分爲如下步驟:
1.單例store的數據在react中能夠經過view組件的屬性(props)不斷由父模塊**「單向」**傳遞給子模塊,造成一個樹狀分流結構。若是咱們把redux比做整個應用的「心肺」 (redux的flux功能像心臟,reducer功能像肺部毛細血管),那麼這個過程能夠比做心臟(store)將氧分子(數據)經過動脈毛細血管(props)送到各個器官組織(view組件)
2.末端的view組件,又能夠經過flux機制,將攜帶交互意圖信息的action反饋給store。這個過程有點像將攜帶代謝產物的「紅細胞」(action)經過靜脈毛細血管又泵迴心髒(store)
3.action流回到store之後,action以參數的形式又被分流到各個具體的reducer組件中,這些reducer一樣構成一個樹狀的hierarchy。這個過程像靜脈血中的紅細胞(action)被運輸到肺部毛細血管(reducer組件)
4.接收到action後,各個child reducer以返回值的形式,將最新的state返回給parent reducer,最終確保整個單例store的全部數據是最新的。這個過程能夠比做肺部毛細血管的血液充氧後,又被從新泵回了心臟
5.回到步驟1
用圖示的方式表達:
圖中A表示Action,V表示View組件,R表示Reducer。
爲了確保咱們比較容易理解程序的全局行爲,或者說提升程序行爲的肯定性(predictable),咱們通常指望具備相似職能的代碼片段被「平鋪」着擺放在一。
所以圖示中相同顏色區域的代碼一般會被放到同一個文件夾/文件中。
另外,一樣出於提升程序的肯定性,redux所遵循的函數式編程鼓勵咱們使用pure function和immutable。