REDUX
1.redux究竟是個(gè)什么玩意 ?
? 如果要談起redux,我們必須要了解什么叫做 函數(shù)式編程 ,其實(shí)我們程序的組件開發(fā)屬于函數(shù)式編程的升級(jí)版,函數(shù)式編程帶給我們的優(yōu)勢(shì)可以說(shuō)非常之多,什么功能劃分更容易,什么維護(hù)更簡(jiǎn)便,什么高內(nèi)聚低耦合等等優(yōu)勢(shì)在此不再贅述,主要談一談函數(shù)式編程的缺點(diǎn)。
1. 函數(shù)式編程容易編程鏈?zhǔn)秸{(diào)用的模式。
function foo(){
var a = funA();
var b = funB();
return funC(b);
}
function funA(arg){
return arg + 1;
}
function funB(arg){
return arg + 2;
}
function funC(arg){
return arg + 3;
}
? 類似于這樣的函數(shù)在開發(fā)之中帶給我們的困擾可以說(shuō)是相當(dāng)之多了,那么問(wèn)題來(lái)了,我們為什么要用這樣的模式編寫函數(shù)那?
? 因?yàn)楹瘮?shù)的作用域是獨(dú)立的, 所以我們?cè)诤瘮?shù)之間進(jìn)行數(shù)據(jù)通訊的時(shí)候往往需要通過(guò)傳遞參數(shù)或者使用bind等方法進(jìn)行參數(shù)傳遞,這樣的方式帶給我們的就是函數(shù)之間的緊密耦合,如何進(jìn)行解耦那,我們需要用到全局變量進(jìn)行函數(shù)之間值的傳遞, 可是這樣真的解決問(wèn)題了么?
? 這樣的做法解決了一個(gè)問(wèn)題,但是其他問(wèn)題就會(huì)如雨后春筍一般冒出來(lái),全局變量浪費(fèi)內(nèi)存,全局變量不安全,全局變量.... ,辦法總比困難多,對(duì)于這樣的數(shù)據(jù)共享我們其實(shí)可以使用訂閱發(fā)布模式解決問(wèn)題,但是訂閱發(fā)布就萬(wàn)無(wú)一失了么?
2. 數(shù)據(jù)驅(qū)動(dòng)模型的實(shí)現(xiàn)。

? 對(duì)于這樣的需求我們往往需要使用訂閱發(fā)布模式進(jìn)行實(shí)現(xiàn),但是訂閱發(fā)布的封裝又出現(xiàn)了n種方案,怎么辦?
? 其實(shí)說(shuō)到這里我們好像知道了一件事,問(wèn)題的解決方案有了,但是我們實(shí)際上是欠缺一個(gè)統(tǒng)一的標(biāo)準(zhǔn)對(duì)我們的需求(函數(shù)與函數(shù)或者組件與組件之間的通訊)進(jìn)行統(tǒng)一,這個(gè)標(biāo)準(zhǔn)不一定是最優(yōu)的但是需要應(yīng)用范圍要廣。
? 這個(gè)時(shí)候flux架構(gòu)出現(xiàn)了。
2. flux架構(gòu)
? flux架構(gòu)就像是眼鏡,你自然知道什么時(shí)候需要他
? flux的橫空出世好像是踏著五彩祥云的至尊寶,拯救萬(wàn)千前端于水火之中,但是這個(gè)至尊寶有點(diǎn)麻煩。

? 這是flux的架構(gòu)圖,你甚至不需要看懂,只需要知道整個(gè)架構(gòu)的復(fù)雜程度還是非常高的,在flux之中想要更改數(shù)據(jù)倉(cāng)庫(kù)(store),我們需要調(diào)用dispather,在dispather之中手動(dòng)調(diào)用 store之中的set方法,去更改狀態(tài),我們?cè)陂_發(fā)企業(yè)級(jí)項(xiàng)目的時(shí)候,往往會(huì)維護(hù)一個(gè)非常龐大的store,這時(shí)候我們面對(duì)這樣異常敏感而且不易排錯(cuò)的功能,可以說(shuō)如履薄冰。
? 然后鋼鐵俠替代至尊寶來(lái)接你了。
3.redux
? 可以說(shuō)redux就是flux架構(gòu)的簡(jiǎn)化版,雖然還是很難,但是相對(duì)flux而言,redux把一些易錯(cuò)的操作進(jìn)行了內(nèi)部封裝,這些封裝使得報(bào)錯(cuò)風(fēng)險(xiǎn)急劇下降。
? 比較現(xiàn)成的東西就一定是量身訂造的東西,雖然redux可以完全獨(dú)立使用,可以配合任何框架實(shí)現(xiàn)基礎(chǔ)功能但是我們最多的使用redux的地方還是在react之中,為啥那?
? 我們考慮的框架有兩款,vue有比較現(xiàn)成的vuex, react那, fb的工程師更推薦使用redux,因?yàn)閞edux和react有更高的契合度有更豐富的合作生態(tài)如 react-redux等。
4. redux使用詳解
**part 1 : 看懂一張圖 **

? 這張圖基本說(shuō)明了使用redux的全部?jī)?nèi)容,但是想要讀懂這張圖可能對(duì)于絕大多數(shù)小伙伴來(lái)說(shuō)比較困難,怎么辦吶? 不要放棄,我們先學(xué)一下基本操作,過(guò)一會(huì)再回頭來(lái)看這張圖。
-
redux 是干嘛的 ?
一句話解釋 : 其實(shí)redux就是用來(lái)進(jìn)行函數(shù),組件之間數(shù)據(jù)共享的。
- redux怎樣進(jìn)行數(shù)據(jù)共享那 ?
一句話解釋 : 就是把一個(gè)
對(duì)象放進(jìn)數(shù)據(jù)倉(cāng)庫(kù)之中。- redux是否實(shí)現(xiàn)了發(fā)布訂閱模式那 ?
一句話解釋 : 實(shí)現(xiàn)了,這是后話。
所以我們大致了解了redux,那么我們用一個(gè)極簡(jiǎn)的翻譯來(lái)看一下這個(gè)圖。
?
這張圖之中尤其要注意的是創(chuàng)建狀態(tài)到狀態(tài)區(qū)分處理器, 這兩個(gè)部分之間的綠色箭頭,在通過(guò)數(shù)據(jù)倉(cāng)庫(kù)時(shí)這個(gè)線是虛的,也就是說(shuō),本質(zhì)上來(lái)講是狀態(tài)區(qū)分處理器最終將狀態(tài)放入了數(shù)據(jù)倉(cāng)庫(kù)之中,可是為什么這條線要先經(jīng)過(guò)數(shù)據(jù)倉(cāng)庫(kù)那 ?
? 敲黑板的重點(diǎn)來(lái)了 :
? 創(chuàng)狀態(tài)這個(gè)功能其實(shí)會(huì)創(chuàng)建一個(gè)對(duì)象,這個(gè)對(duì)象會(huì)被
dispatch方法直接派發(fā)到 數(shù)據(jù)倉(cāng)庫(kù)之中,但是數(shù)據(jù)倉(cāng)庫(kù)又需要去進(jìn)行一個(gè)狀態(tài)區(qū)分和處理,這個(gè)區(qū)分和處理是被直接集成在數(shù)據(jù)倉(cāng)庫(kù)之中的,相當(dāng)于倉(cāng)庫(kù)分揀員 , 這個(gè)分揀員會(huì)自動(dòng)將創(chuàng)建好的對(duì)象進(jìn)行分類,分類后放入倉(cāng)庫(kù)。
數(shù)據(jù)倉(cāng)庫(kù)內(nèi)部一旦發(fā)生改變了,那么視圖就會(huì)發(fā)生相應(yīng)的改變,這就是redux完整的流程。
但是這個(gè)完整的流程之中有非常之多的注意事項(xiàng),如果你已經(jīng)理解了以上的內(nèi)容,那么就可以繼續(xù)向下學(xué)習(xí)redux操作實(shí)例了。
為了方便操作,我們使用 create-react-app 腳手架工具搭建react環(huán)境,并使用 redux進(jìn)行開發(fā) , 編寫redux實(shí)例,同時(shí)為了使用的安全和嚴(yán)謹(jǐn),請(qǐng)務(wù)必參考 redux官方文檔,其余野路子博客不建議查看。
part 2 : 記得三個(gè)單詞
? 1. action 這貨就是我們剛才說(shuō)的數(shù)據(jù)對(duì)象,這個(gè)對(duì)象就是JavaScript的單純的對(duì)象。 就是下面這樣的
var action = {
name : "一個(gè)對(duì)象"
}
2. action 還有一些小小的矯情,就是必須有某些東西,這個(gè)東西就叫做 `type`, 我們?cè)趧?chuàng)建action的時(shí)候通常會(huì)創(chuàng)建這樣的一個(gè)對(duì)象
let action = {
type : MY_FIRST_ACTION,
payload : {
text : "隨便寫一些文本"
}
}
我們寫的這個(gè)對(duì)象大概就是action了,但是我們想要?jiǎng)?chuàng)建茫茫多個(gè)action怎么辦吶 ? 記得我們有一個(gè)創(chuàng)建器就好了,這個(gè)創(chuàng)建器叫做 actionCreater
3. actionCreate長(zhǎng)成這樣 , 我們通常定義 action之中type的時(shí)候會(huì)使用`常量`。
action.js
/*
* 常量定義,這個(gè)常量?jī)H代表狀態(tài)。
*/
export const INCREASE_NUMBER = "INCREASE_NUMBER";
export const REDUCE_NUMBER = "REDUCE_NUMBER";
export const INIT_NUMBER = "INIT_NUMBER";
export function increaseNumber(number){
return {
type : INCREASE_NUMBER,
payload : {
number
}
}
}
export function reduceNumber(number){
return {
type : REDUCE_NUMBER,
payload : {
number
}
}
}
4. 我們要設(shè)計(jì)一下我們當(dāng)前state 的數(shù)據(jù)結(jié)構(gòu),這個(gè)數(shù)據(jù)結(jié)構(gòu)方便我們后續(xù)的操作。
{
calculationNumber :{
type : INIT_NUMBER,
payload : {
number : 0
}
}
}
這大概就是一個(gè)及其簡(jiǎn)單的數(shù)據(jù)結(jié)構(gòu)了。
5. 開發(fā)狀態(tài)區(qū)分處理器 reducer
? reducer接受兩個(gè)參數(shù) reducer( prevState, state) , 即為原始狀態(tài)和更新狀態(tài) , 請(qǐng)務(wù)必記住reducer的特性,reducer是一個(gè)純函數(shù),這意味著 同樣的輸入,同樣的輸出,如果輸入同樣的內(nèi)容那么輸出一定是一致的,這就是純函數(shù)。 在這里不能調(diào)用 Date.now() ,或者 Math.random() 等方法。
reducer.js
import {
INCREASE_NUMBER,
REDUCE_NUMBER,
INIT_NUMBER
} from "./action"
function calculation(state = initialState , action){
switch(action.type){
case INCREASE_NUMBER :
return Object.assign({},state,{
...action,
payload : {
number : state.payload.number ++
}
});
case REDUCE_NUMBER :
return Object.assign({},state,{
...action,
payload : {
number : state.payload.number --
}
});
default : return state;
}
}
export calculation;
6. 最后我們引入我們的主角
store.getState()用來(lái)獲取store完整數(shù)據(jù)。
store.subscribe() 用來(lái)監(jiān)聽完整數(shù)據(jù)。
import {createStore} from "redux";
import reducer from "./reducer";
let store = createStore(reducer);