React官方網站是這樣形容React的,A JavaScript library for building user interfaces。React其實是一個編寫頁面的UI框架,或者說他只是一個UI的library,一個庫而已。html
雖然React只是一個UI的library,不過他渲染頁面的方式倒是值得咱們學習的。經過JSX動態的生成DOM來渲染頁面UI。他沒有架構,沒有模板,沒有設計模式,沒有路由,也沒有數據管理,也能夠說他除了渲染UI之外什麼都作不了。npm
可是對於一個大型的複雜的網站來講,設計模式和數據管理這兩個是缺一不可的,所以若是咱們只使用React是沒有辦法開發大型網站應用的。redux
好比下面這張圖,他表明的是React的組件結構,網站是經過組件樹的形式渲染UI的。設計模式
咱們都知道React中數據流向是單向的,並且老是自上而下傳遞的,能夠經過props將數據從父組件傳遞給子組件,可是假設咱們須要將組件樹最底層的Banner節點的數據傳遞給最頂層的Index,這個時候組件之間該如何通訊呢。微信
遵循React的單向數據傳遞原則咱們是沒有辦法直接傳遞數據的不過咱們能夠經過函數回調的方式,經過調用父組件的函數一層一層的向上傳遞。也就是Banner調用回調將數據傳給Main,Main再經過回調將數據傳給Index。markdown
實際上在大型的網站中相似這樣須要共享數據的狀況很是常見,若是咱們經過回調函數這樣來一層一層傳遞你會發現整個網站的代碼會變得很是噁心。基本上你的代碼就是沒法維護的狀態。並且這樣處理數據的開銷是很是巨大的。一個不當心頗有可能陷入無限死循環中。架構
因此當咱們的網站複雜到必定程度的時候咱們就須要設計模式了,可能以前你已經知道MVC, MVVM, MV*。可是針對React咱們還可使用一種更加符合React設計思想的架構模式,Redux。框架
Redux是一種設計模式同時也是一種項目架構方案,他不依賴任何庫或者任何框架,他不只能夠在React中使用甚至在Angular和Vue中也可使用。異步
使用Redux架構來講全部的組件基本不會互相通訊了,數據放在一個叫作store的數據倉庫中存儲。函數
經過使用Redux咱們能夠剝離出組件中的數據(state),將全部數據統一存放在Redux數據(store)倉庫中,若是組件中哪個組件須要使用到數據,這個組件能夠去數據倉庫中自行認領有個高大上的叫法是訂閱。若是組件中對store中的數據進行了更新那麼store會向訂閱了這個數據的全部組件推送最新的數據,這就是Redux的原理。
Redux就是數據倉庫,他把數據統一保存起來,在隔離的數據和UI的同時還處理了他們之間的關係。
使用Redux的目的是讓狀態state的變化可控可預測。雖然從原理來看Redux彷佛挺簡單的可是想要了解他的工做流程就比較麻煩了。
這主要是由於他的數據流動方式不是特別直觀,有點相似事件驅動的方式,咱們知道事件驅動開發最困難的地方是在調試。Redux中使用了不少晦澀難懂的專業術語好比Action,Reducer,Dispatch等,瞭解這些名詞以前咱們很難把握Redux的方向。還有就是Redux的文檔並不親民,處處都是新概念,好比說純函數,flux,observable,immutable這些概念張口就來徹底不去考慮別人是否能夠看懂。
通常來講使用Redux都會建立一個用於存放數據的Store,在這個Store中有若干個Reducer,而後咱們須要使用React組件來渲染UI,除此以外還會有若干個和Reducer對應的Action指令。
Store中的Reducer組合在一塊兒就造成了項目中的數據倉庫。Redux稱之爲State也就是數據。React組件經過訂閱(subscribe )Store來得到數據,而後使用數據來渲染UI,UI經過顯示器顯示給用戶,用戶經過鼠標和鍵盤與組件進行交互,在交互中不可避免須要改變數據,在React中數據的流動是單向的,因此對數據來講React組件只有讀取權限,沒有書寫權限UI組件不能夠直接訪問Store修改數據。
因此UI必須向Store發送Action指令,來讓Store本身修改本身,這個指令的分發過程就叫作dispatch。Action指令到達store以後可能會通過若干個middleware中間件進行數據的預處理,對於數據的異步處理也是在這裏進行的,預處理事後數據就會連同action一塊兒傳遞給reducer,reducer會按照Action中描述的指令來更新數據state,當state更新好之後Store就會把數據推送給訂閱了本身的組件,組件會根據新的數據從新渲染UI, 用戶就能看到變化了。能夠看到在實際工做中Redux架構仍是相對複雜的。
上面的描述仍是比較複雜的,不過不要慌,下面咱們來簡化一下這張圖,只保留幾個主要部件,經過學習簡化的流程來了解Redux。
簡化後的六層咱們只保留Reducer,Store,React組件,Actions這四個部分。爲了更加清晰咱們這裏將Reducer從Store中移了出來,實際上他們是一體的。
Store中保存的是全局數據,對於Redux項目來講有且只有一個Store,咱們能夠把它看作一個帶有推送功能的數據倉庫。咱們能夠借用微信的朋友圈來理解這個概念。好比你加了某我的的好友,只要這我的一發朋友圈他的狀態就會立刻推送到你。加好友就是數據訂閱,發朋友圈就是數據推送。
Reducer是幫助Store處理數據的方法,他是一個方法是一個過程是一個函數不是一個具體存在的對象,Reducer能夠幫助Store初始化數據,修改數據,刪除數據,你可能會好奇咱們爲何要使用Reducer這麼麻煩的方式來處理數據而不是直接在Store中進行修改,其實緣由也很簡單。好比你看到你朋友的朋友圈有錯別字,你是沒辦法直接修改它的朋友圈狀態的。
任何UI級別的組件都沒有權限修改Store中的數據,根據數據單向流動的原則他們是隻讀不能寫的,你只能給他打電話或者發短通知他讓他來修改,他修改後會重新推送給你。給他打電話或者發短信通知他就是Action,給他打電話或者發短信通知他的這個過程就是dispatch Action消息的分發。他本身修改朋友圈的過程就是reducer。
最後他修改好以後微信會重新將消息通送給你,這就是訂閱和推送。
因此Store就是Redux中具備推送功能的數據倉庫,Reducer是Store處理數據的方法能夠幫助Store實現數據的初始化,修改或者刪除,Actions就是數據更新的指令,他會告訴Reducer如何去處理數據因此Redux的流程其實很清晰。
首先建立數據倉庫Store,Reducer會同時初始化數據state。React Component會訂閱Store,Store中的數據就會被推送過來,而後渲染UI.
若是組件須要更改數據他會發送一個Action,這個過程就叫作dispatch。Action會以事件驅動的方式被Store所截獲,Store會將本身當前的數據以及指令傳遞給Reducer,由Reducer去更新數據。Reducer更新完成之後就會向Store輸出一個新的state,Store取到新的state以後就會向訂閱了本身的React組件推送這個新的數據。而後從新再次渲染UI。這就是一個完整的Redux工做流程。
Redux是一種設計模式同時也是一種項目架構方案,他不依賴任何庫或者任何框架,只是你們習慣於將Redux和React放在一塊兒使用。這裏咱們介紹一下Redux的使用,爲了不混淆咱們不使用任何框架。
首先你能夠經過npm在項目中安裝redux插件,前面說過Store就是保存數據的地方,整個應用只能有一個Store, Redux提供createStore這個函數,用來生成Store。
import { createStore } from 'redux'
const store = createStore(fn);
複製代碼
這裏createStore須要接收一個函數,這個函數就是用來處理action操做的也就是咱們以前說的Reducer,因此他須要接收action參數,由於他是幫助Store處理數據的,因此也須要接收源數據,返回值是更新後的數據。
const fn = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
複製代碼
在須要使用數據的位置咱們能夠經過getState來獲取數據,經過subscribe訂閱來監聽數據的變化,由於Redux是一種發佈訂閱模式,只有監聽纔會獲取到。
store.subscribe(() => {
const state = store.getState();
}))
複製代碼
須要更數據時,須要使用dispatch配合action來分發。咱們約定action須要是一個擁有type屬性的對象,type來表示要操做的類型,若是傳遞參數咱們通常將參數放在payload屬性中。
const action = {
type: 'INCREMENT',
payload: '參數',
};
store.dispatch(action);
複製代碼
這樣咱們當調用store.dispatch時,Redux會將action傳遞給Reducer,Reducer經過自身的邏輯處理返回新的state,而後Redux記錄這個新的state而且推送消息給訂閱了本身的組件。也就是會觸發subscribe中傳入的函數。函數中能夠經過store.getState()得到新的state值,完成頁面更新。
假設咱們頁面中有一個button按鈕和一個div元素,這個元素用來展現一個數字,初始值爲0,當咱們點擊button按鈕的時候讓div中顯示的數字增長。
<div id="count"></div>
<button id="button">按鈕</button>
複製代碼
js代碼以下, 咱們首先定義reducer,在裏面判斷若是type爲INCREMENT就讓state+1,而後經過createStore建立store傳入處理函數reducer。
接着訂閱state,當state變動時獲取頁面div元素更新div的內容爲state的值。
最後點擊按鈕的時候咱們經過dispatch來分發action。
var reducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
default:
return state
}
}
var store = createStore(reducer);
store.subscribe(() => {
document.querySelector('#count').innerHTML = store.getState();
});
document.querySelector('#button').addEventListener('click', function () {
store.dispatch({type: 'INCREMENT'});
});
複製代碼
這就是Redux的一個基本使用過程,你懂了麼?
那具體何時須要使用到Redux呢?
組件須要共享數據或者共享狀態(state)的時候;
某一個組件在任何地方都須要被隨時訪問的時候。
某一個組件須要改變另外一個組件狀態的時候。
網站支持國際化語言切換,登陸數據共享的狀況下。
知足上面一種或幾種狀況建議使用redux,若是你還在考慮項目要不要使用redux我給的建議就是不要。技術是爲了服務業務。爲了不設計的頭重腳輕,建議只有在須要的時候才引入新概念,切忌爲了使用而使用。