父(外部)組件向子(內部)組件傳遞數據是經過自定義屬性props值的方式進行實現的,而且在子組件內部經過this.props進行獲取,它並不能直接被修改,若是想要修改,那麼得經過React內置的一個setState的方法進行觸發javascript
而子組件想要傳遞數據給父組件,是經過調用父組件的方法進行通訊前端
一個組件可能存在着不少狀態,組件之間有時須要進行通訊,對於多個組件狀態維護,若是依舊用原來的方式,那麼就比較複雜了的java
那麼Redux正好解決了這一問題.我的以爲,Redux學起來很抽象,的確是塊硬骨頭,可是高山始終是要越過的web
下面就一塊兒來學習下Redux的數據庫
您將在本文中學習到數組
Redux是什麼bash
Redux的使用場景以及與不使用Redux的靈魂對比服務器
Redux的工做流程架構
Redux的設計基本原則app
本篇雖不涉及代碼層面上的,可是對後續編碼Redux很是重要,磨刀不誤砍柴工
若是想閱讀體驗更好,可戳連接,React進階(1)-理解Redux
Redux是什麼?
官方解釋:JavaScript應用程序的可預測的狀態容器(一個管理應用程序狀態的框架)
通俗一點:管理組件公共數據狀態的容器(倉庫/區域)
解決的問題: 當應用組件擁有多個狀態,而且組件之間須要共享數據狀態時,從原始的組件傳遞數據的方式中解脫出來,集中管理組件的狀態
你能夠把Redux理解爲一個倉庫,房產中介.擁有不少共享的房源的一個管理者,後面會有具體的例子
Redux的使用場景
從上面提到的Redux解決問題能夠看出,Redux只是用來管理和維護組件的狀態的
React開發的模式就是組件化開發,將一個大的應用拆分紅若干個小的應用,而後拼接成一個大的應用,而編寫一個大小應用就是在編寫各個大小組件
而組件的顯示形態又取決於它的狀態,這不區分於不管是外部的props仍是內部的state,而組件之間有時須要共享傳遞數據,Redux僅僅就是用來管理這些組件的狀態的
在一些開發者眼裏,項目裏要是沒有用到Redux,就以爲很low,要麼把Redux捧得高高在上,要麼說都已經快0202年了,都用React hook了,鄙視得不行,我的以爲徹底沒有必要.
React與Redux自己就是解決兩個不一樣方向的問題,某種程度上講,React能夠視爲MVC架構中的視圖層V,而Redux則是model數據層M,而C層每每是鏈接視圖層和model的鏈接器,每每處理前端數據請求,路由跳轉等業務邏輯
即便不用Redux,照樣能作小應用,只是略複雜繁瑣一些而已,下面會介紹他們之間的對比
那麼對於技術選型,何時用Redux何時不用?
如下是選用Redux的場景:
項目很是龐大,公共組件與業務組件很是多,用戶的使用方式比較複雜
不一樣身份的用戶角色權限管理(例如不少後臺管理系統,普通用戶,超級管理員,VIP用戶)讀,寫權限管理等
多個用戶之間能夠協做實時操做(不少那種在線敏捷協做辦公文檔工具,多個用戶能夠實時編輯操做同一份文檔等的,例如石墨文檔,語雀,confluence.釘釘等的)
須要與服務器大量的交互,或者使用了webscoket的,聊天,直播等應用的
視圖層view須要從多個來源獲取數據
....只要你發現React解決不了的問題,遇到多交互,多數據源的,那麼就能夠考慮使用Redux的
反之,則如下則是沒有必要使用Redux
UI層很是簡單,只是用於渲染,無複雜的數據交互,依賴外部的props就能夠渲染組件
用戶的使用方式比較簡單,頁面之間比較獨立,沒有互相協做
與服務器之間沒有大量交互
當你發現使用React實在解決不了的問題,在各個組件之間傳遞數據很是複雜,很痛苦時,那麼就能夠考慮使用Redux了的,只要你hold住,沒有所謂的高大上技術,只有適合本身業務的技術
盲目引入Redux只會增長項目的複雜度,引入新的技術應該是按部就班的
不使用Redux與使用Redux的靈魂對比
下面這張組件樹狀態圖的對比就很好的解釋了使用Redux與不使用Redux的區別
一個React應用(例如:pc網站,手機app應用,後臺管理系統等用React技術棧構建的應用) 其實就是一顆由組件構成的樹,如上圖所示, 在這顆樹的根結點,最頂層的組件就是該應用的自己,因爲組件都是以樹結構組織起來的,當每一個組件被渲染時,它都會遞歸地渲染下級組件假設紅色圓圈表明的是一個應用的子組件,若是想要把該紅色圓圈組件的狀態數據傳遞給父級或者非父級組件,它是經過調用父組件的方法來實現,這樣一層一層往上傳,若是組件樹很龐大的話,那麼就會變得很是繁瑣
在小型項目中,Redux並非必需的,可是使用Redux倒是一勞永逸的,管理組件的狀態方便得多,對於大型應用來講,單純使用原始的數據傳遞方式
那麼組件之間的傳值會變得很是複雜,若是要作一個大型的應用,那麼就須要在React的基礎上配置一個數據層的框架進行結合的使用
若是改成右邊的Redux處理方式,將紅色圓圈組件的狀態數據放到一個Store倉庫當中集中進行管理,哪一個組件須要的話,直接派發給哪一個組件就能夠了的.
在Redux中,要求把組件的數據放到公共的存儲倉庫(區域)當中,讓組件儘量的減小狀態數據存儲,換而言之,全部組件自身內部狀態數據都不放在state裏面了,把它放到Store這樣的一個存儲倉庫當中去
其實本質上來講,是放到reducer裏面去管理,Store從Reducer中拿到返回的數據state,最後供外部組件的取用
當紅色圓圈組件想要改變數據傳遞給其餘組件時,只須要去改變Store裏面的存儲紅色圓圈組件的數據就能夠了
一旦Store公共存儲的狀態數據發生改變了的,因爲其餘組件是公用Store的數據,那麼其餘組件就會感知到Store的數據發生了改變,從而自身組件也會跟着改變
只要Store公共存儲區域的數據發生改變,凡是共用了Store裏面的數據的組件都會從新的取數據
這樣一來,紅色圓圈組件的數據就很是容易的傳遞給其餘組件了,不管是它的父級組件仍是兄弟,非兄弟組件的
Redux就是把組件的數據放到一個公共的區域(倉庫)中進行存儲,當改變Store存儲區域裏面的數據時,其餘組件若是用到了公共區域的數據,那麼就會感知到數據的變化,它會自動的更新取Store中最新的數據
這樣話,不管你的應用組件嵌套得有多麼複雜,多麼深,走的流程都是同樣的,組件之間並不會干擾,低耦合的效果
當組件一修改,把修改的數據放到Store當中,而其餘組件又從Store當中再來取,這樣的話,組件與組件之間並非直接進行通訊的,是經過這麼一個store中間角色來實現數據的傳遞共享的.
這樣的話,組件的數據傳遞就簡單多了的,也避免了組件與組件之間頻繁通訊,容易產生混亂的問題
Redux實際上是Flux數據框架的一個替代演進,一樣強調的是單向的數據源,保持狀態只具有讀的能力,而數據改變只能經過純函數完成基本,這和原先中React的UI=render(data)徹底吻合.
React與Redux是兩個獨立的框架,前者是用於組件視圖層的渲染,然後者是管理組件的數據
Redux的工做流程
如今已經知道了使用Redux與不使用Redux的區別,那麼如今是時候來了解一下Redux的工做流程了,下面這個流程圖對於理解Redux很重要 先附上一張Redux工做流的流程圖:之後會在代碼中逐步的體現
上面的Redux工做流圖中,以中間爲準:包括了Store,ReactComponents,Actions Creators,以及Reducers其中Store表明的就是負責組件存儲全部公共狀態的數據,全局只有一個Store.(這裏你能夠把它理解爲相似生活當中中介公司管理房源的倉庫(數據庫)的區域經理)
實質上:store就是把Reducer關聯到一塊兒的一個對象,它提供dispatch(action)方法更新state,以及getState方法獲取state
React Components:指的是頁面上的任意一個組件(你能夠理解爲小區公寓樓裏的每一個房間,而你就是住在裏面的租房用戶)
Actions Creators:具體要幹什麼事情,觸發的動做,能夠看作一個交互動做,改變應用狀態或view的更新,都須要經過觸發action來實現,Action的執行結果就是調用Dispatch來處理相應的事情,實現頁面視圖view的更新,惟一的辦法就是調用dispatch派發action
它是一個javascript對象,是用來描述事件的行爲的,對象裏記錄了相關的信息,例如:todolist的添加,刪除list的這個具體操做,就是一個action
(當你想要提出換房的時候,跟中介公司管理房源的經理說,你要換個帶有沙發,電視,配備廚房的兩室一廳的房子,由於增長人口了,現有的房子住不下了的,你要作的什麼事情,提出的條件信息就是數據),這個動做能夠理解爲actions creators
在你提出換房的時候,房產中介公司經理雖然手握不少房源,可是他也沒有辦法記得全部的房子相關信息,它須要去數據庫(倉庫)裏去查,你經常看到中介小哥帶你看房的時候
手上拿一個單子,Excel表格跟你介紹房源的時候,你能夠把這個單子,Excel表格理解爲一個實時記錄本,只要有房子出租去了,這個表格就會實時更新(新舊信息的核實對比),返回一張新的房源信息表單給房產中介的經理
Reducer:能夠把上面的用於實時更新記錄房源信息的記錄本稱爲Reducer,它只用做於根據舊的房源與提出新的需求(動做),老是會返回一張新的記錄本給房產中介經理
實質上:Reducer是根據action發出的type(動做類型)來作什麼事(返回最新的state給store等邏輯操做)
如今概括一下整個流程:
我(租客/組件React Component)想要換一個xxx信息的房子(Actions creators,具體要作的什麼事情),房產中介經理收到了請求,他得根據你提供的一些需求信息去找相應的房源信息
可是房源太多,須要藉助一個實時的記錄本去查看符合條件的房源信息,當查到符合條件的信息後,這個記錄本(Reducer)把最新的信息會返回給房產經理(Store),最終把信息返回給用戶React Components,實現房子替換的更新
雖然文字囉嗦了點:可是Redux就是這麼一回事,我要換大房子,房產中介經理聽到後,它去記錄本裏面去查,查到以後,返回到房產中介經理,而後最終在返回給我,實現房子的替換
那麼轉換爲代碼理解:
頁面上的一個組件,想要獲取更新Store中的數據,跟Store說,我點擊這個按鈕,要更新這個組件的數據,要幹什麼事情,作的這個具體動做就是Actions Creators,這時會派發(dispatch) 該動做(action)給Store,Store會去Reducer裏面去查一下,Reducer會返回一個新的結果給Store,Store拿到最新的數據結果後,返回給頁面上的組件,實現頁面組件的更新
你們能夠先仔細體會上面這段文字的含義,在後續的實例代碼中,在回過頭來對比着代碼與文字進行理解的,後續還會在拿出來的
Redux的設計基本原則
在Redux中有如下幾個設計基本原則
單向數據流
惟一數據源
保持狀態只讀
數據的改變只能經過純函數reducer來完成
單向數據流: 這個其實與props不能直接被修改同樣,在父組件向子組件傳遞數據時是經過屬性的方式進行傳遞的,而子組件內部經過this.props進行接收,可是外部傳遞過來的props屬性不能直接被修改,若想要修改,須要藉助React內置的setState方法進行觸發
惟一數據源: 它指的是組件的應用狀態數據應該只存在惟一的Store上,這一點是不一樣於Flux的,在Flux中容許有多個store。而在Redux中整個組件的應用只保持一個Store,全部組件的數據源就是這個Store上的狀態,能夠將它Store理解爲一個全局的變量對象
保持狀態state可讀: 不能直接的去修改狀態,要修改Store的狀態,必需要經過派發(dispatch)一個action對象去完成
而後組件渲染的對應的界面要更改的話,實際更改的就是組件的狀態,若是狀態都是隻能讀不能修改的話,那麼界面就不會更新變化了
想要更改用戶界面的渲染,就要改變組件的應用狀態,但時改變組件狀態的方法不是直接去修改狀態上的值,而是建立一個新的狀態對象返回給Redux,由Redux完成新的狀態的組裝
組件數據的改變只能經過純函數完成
所謂的純函數,就是指Reducer,而Redux某種程度上講,它是Reducer+Flux的組合,其中這Redux的Red表明就是Reducer,而ux就是Flux,可是又不一樣於Flux,它更像是Flux的一個實現,演進。它是爲了描述Action如何改變組件的狀態的
這也是爲何Redux這個名稱比較抽象的緣由,其中Reducer相似一個數組中的迭代器函數reduce
var arr = [1,2,3,4,5,6]
var sum = arr.reduce(function reducer(prevValue, currentValue,index,array){
console.log(`上一次調用回調返回的值(或者是提供的初始值): ${prevValue},數組中當前被處理的元素: ${currentValue}, 當前元素在數組中的索引: ${index}, 調用的數組: ${array}`);
return prevValue+currentValue;
},0)
console.log(sum); // 21
VM1742:3 上一次調用回調返回的值(或者是提供的初始值): 0,數組中當前被處理的元素: 1, 當前元素在數組中的索引: 0, 調用的數組: 1,2,3,4,5,6
VM1742:3 上一次調用回調返回的值(或者是提供的初始值): 1,數組中當前被處理的元素: 2, 當前元素在數組中的索引: 1, 調用的數組: 1,2,3,4,5,6
VM1742:3 上一次調用回調返回的值(或者是提供的初始值): 3,數組中當前被處理的元素: 3, 當前元素在數組中的索引: 2, 調用的數組: 1,2,3,4,5,6
VM1742:3 上一次調用回調返回的值(或者是提供的初始值): 6,數組中當前被處理的元素: 4, 當前元素在數組中的索引: 3, 調用的數組: 1,2,3,4,5,6
VM1742:3 上一次調用回調返回的值(或者是提供的初始值): 10,數組中當前被處理的元素: 5, 當前元素在數組中的索引: 4, 調用的數組: 1,2,3,4,5,6
VM1742:3 上一次調用回調返回的值(或者是提供的初始值): 15,數組中當前被處理的元素: 6, 當前元素在數組中的索引: 5, 調用的數組: 1,2,3,4,5,6
VM1742:6 21
複製代碼
上面的代碼中是作一個簡單的累加,reducer函數接收四個參數,第一個參數是上一次調用返回的結果,第二個參數是當前被處理的元素的值,第三個是當前元素在數組中的索引,第四個是調用的原數組
這個reduce的方法接收一個函數做爲累加器,reduce 爲數組中的每個元素依次執行回調函數
而在Redux中,每一個reducer純函數以下所示 其中reducer函數的第一個參數state是指當前的狀態值,而第二個參數action是接收到的action對象
而reducer函數要作的事情就是根據state和action的值產生一個新的對象返回給Store,它是定義整個組件應用狀態如何更改,根據Action動做行爲去更新Store中的狀態
注意的是reducer必須是純函數,換句話說,reducer函數的返回結果必須徹底由參數state和action決定,並且不產生任何的反作用,也不能修改參數state和action對象
以下一個典型的reducer示例,reducer只是一個函數名稱,你是能夠任意取的,以下一個計數的counter純函數
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
複製代碼
從上面的例子看得出,reducer函數不光接受action爲參數,還接受state參數,也就是說,Redux中的reduce函數只負責計算組件的狀態,卻不負責存儲組件的狀態
在Reducer函數中每每包含action.type爲判斷條件的if-else或者switch語句,根據action,老是返回一個新的狀態,這個新的狀態的結果返回給store,store就會將原來上一次的state進行替換更新,最終達到改變state這麼一個過程
本節主要介紹了Redux,它與React是兩個獨立的產品,兩個框架作的事情的方向不同,React是用做於視圖層的渲染,也至關於MVC中的V層,而Redux它是用於管理組件公共數據的Model層,更近一步講,它是Reducer與Flux的一種結合,改進.
對比了使用Redux與不使用Redux的區別,以及Redux的工做流,最後Redux的設計基本原則,其中前兩個,我的以爲對於理解Redux是很是重要的
固然如今也可使用高階組件,React hooks的寫法,能夠不用Redux了的,也有相似於dva這樣的框架,基於Redux以及中間件(Redux-saga)的數據流方案
可是Redux依然是主流,只要你可以應付項目中開發需求,哪一個用得爽就用哪一個的,Redux雖然確實是繞了一些,有時候在各個文件之間進行來回切換,對於模塊化的拆分,若是不是很清楚Redux的使用流程,不管是後續維護仍是迭代升級,都挺痛苦的
本篇並非什麼高大上的內容,比較淺顯,概念性的文字比較多,後續會結合具體的代碼進一步理解Redux